﻿using System;
using UnityEngine;

namespace RootMotion.FinalIK
{
	// Token: 0x02000180 RID: 384
	[Serializable]
	public class IKSolverVR : IKSolver
	{
		// Token: 0x0600074C RID: 1868 RVA: 0x00025D78 File Offset: 0x00024178
		public void SetToReferences(VRIK.References references)
		{
			if (!references.isFilled)
			{
				Debug.LogError("Invalid references, one or more Transforms are missing.");
				return;
			}
			this.solverTransforms = references.GetTransforms();
			this.hasNeck = (this.solverTransforms[4] != null);
			this.hasShoulders = (this.solverTransforms[6] != null && this.solverTransforms[10] != null);
			this.hasToes = (this.solverTransforms[17] != null && this.solverTransforms[21] != null);
			this.readPositions = new Vector3[this.solverTransforms.Length];
			this.readRotations = new Quaternion[this.solverTransforms.Length];
			this.DefaultAnimationCurves();
			this.GuessHandOrientations(references, true);
		}

		// Token: 0x0600074D RID: 1869 RVA: 0x00025E48 File Offset: 0x00024248
		public void GuessHandOrientations(VRIK.References references, bool onlyIfZero)
		{
			if (!references.isFilled)
			{
				Debug.LogWarning("VRIK References are not filled in, can not guess hand orientations. Right-click on VRIK header and slect 'Guess Hand Orientations' when you have filled in the References.");
				return;
			}
			if (this.leftArm.wristToPalmAxis == Vector3.zero || !onlyIfZero)
			{
				this.leftArm.wristToPalmAxis = this.GuessWristToPalmAxis(references.leftHand, references.leftForearm);
			}
			if (this.leftArm.palmToThumbAxis == Vector3.zero || !onlyIfZero)
			{
				this.leftArm.palmToThumbAxis = this.GuessPalmToThumbAxis(references.leftHand, references.leftForearm);
			}
			if (this.rightArm.wristToPalmAxis == Vector3.zero || !onlyIfZero)
			{
				this.rightArm.wristToPalmAxis = this.GuessWristToPalmAxis(references.rightHand, references.rightForearm);
			}
			if (this.rightArm.palmToThumbAxis == Vector3.zero || !onlyIfZero)
			{
				this.rightArm.palmToThumbAxis = this.GuessPalmToThumbAxis(references.rightHand, references.rightForearm);
			}
		}

		// Token: 0x0600074E RID: 1870 RVA: 0x00025F60 File Offset: 0x00024360
		public void DefaultAnimationCurves()
		{
			if (this.locomotion.stepHeight == null)
			{
				this.locomotion.stepHeight = new AnimationCurve();
			}
			if (this.locomotion.heelHeight == null)
			{
				this.locomotion.heelHeight = new AnimationCurve();
			}
			if (this.locomotion.stepHeight.keys.Length == 0)
			{
				this.locomotion.stepHeight.keys = IKSolverVR.GetSineKeyframes(0.03f);
			}
			if (this.locomotion.heelHeight.keys.Length == 0)
			{
				this.locomotion.heelHeight.keys = IKSolverVR.GetSineKeyframes(0.03f);
			}
		}

		// Token: 0x0600074F RID: 1871 RVA: 0x00026010 File Offset: 0x00024410
		public void AddPositionOffset(IKSolverVR.PositionOffset positionOffset, Vector3 value)
		{
			switch (positionOffset)
			{
			case IKSolverVR.PositionOffset.Pelvis:
				this.spine.pelvisPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.Chest:
				this.spine.chestPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.Head:
				this.spine.headPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.LeftHand:
				this.leftArm.handPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.RightHand:
				this.rightArm.handPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.LeftFoot:
				this.leftLeg.footPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.RightFoot:
				this.rightLeg.footPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.LeftHeel:
				this.leftLeg.heelPositionOffset += value;
				return;
			case IKSolverVR.PositionOffset.RightHeel:
				this.rightLeg.heelPositionOffset += value;
				return;
			default:
				return;
			}
		}

		// Token: 0x06000750 RID: 1872 RVA: 0x00026124 File Offset: 0x00024524
		public void AddRotationOffset(IKSolverVR.RotationOffset rotationOffset, Vector3 value)
		{
			this.AddRotationOffset(rotationOffset, Quaternion.Euler(value));
		}

		// Token: 0x06000751 RID: 1873 RVA: 0x00026134 File Offset: 0x00024534
		public void AddRotationOffset(IKSolverVR.RotationOffset rotationOffset, Quaternion value)
		{
			if (rotationOffset == IKSolverVR.RotationOffset.Pelvis)
			{
				this.spine.pelvisRotationOffset = value * this.spine.pelvisRotationOffset;
				return;
			}
			if (rotationOffset == IKSolverVR.RotationOffset.Chest)
			{
				this.spine.chestRotationOffset = value * this.spine.chestRotationOffset;
				return;
			}
			if (rotationOffset != IKSolverVR.RotationOffset.Head)
			{
				return;
			}
			this.spine.headRotationOffset = value * this.spine.headRotationOffset;
		}

		// Token: 0x06000752 RID: 1874 RVA: 0x000261B4 File Offset: 0x000245B4
		public void Reset()
		{
			this.UpdateSolverTransforms();
			this.Read(this.readPositions, this.readRotations, this.hasNeck, this.hasShoulders, this.hasToes);
			this.spine.faceDirection = this.rootBone.readRotation * Vector3.forward;
			this.locomotion.Reset(this.readPositions, this.readRotations);
			this.raycastOriginPelvis = this.spine.pelvis.readPosition;
		}

		// Token: 0x06000753 RID: 1875 RVA: 0x00026238 File Offset: 0x00024638
		public override void StoreDefaultLocalState()
		{
			this.defaultPelvisLocalPosition = this.solverTransforms[1].localPosition;
			for (int i = 1; i < this.solverTransforms.Length; i++)
			{
				if (this.solverTransforms[i] != null)
				{
					this.defaultLocalRotations[i - 1] = this.solverTransforms[i].localRotation;
				}
			}
		}

		// Token: 0x06000754 RID: 1876 RVA: 0x000262A4 File Offset: 0x000246A4
		public override void FixTransforms()
		{
			this.solverTransforms[1].localPosition = this.defaultPelvisLocalPosition;
			for (int i = 1; i < this.solverTransforms.Length; i++)
			{
				if (this.solverTransforms[i] != null)
				{
					this.solverTransforms[i].localRotation = this.defaultLocalRotations[i - 1];
				}
			}
		}

		// Token: 0x06000755 RID: 1877 RVA: 0x00026310 File Offset: 0x00024710
		public override IKSolver.Point[] GetPoints()
		{
			Debug.LogError("GetPoints() is not applicable to IKSolverVR.");
			return null;
		}

		// Token: 0x06000756 RID: 1878 RVA: 0x0002631D File Offset: 0x0002471D
		public override IKSolver.Point GetPoint(Transform transform)
		{
			Debug.LogError("GetPoint is not applicable to IKSolverVR.");
			return null;
		}

		// Token: 0x06000757 RID: 1879 RVA: 0x0002632C File Offset: 0x0002472C
		public override bool IsValid(ref string message)
		{
			if (this.solverTransforms == null || this.solverTransforms.Length == 0)
			{
				message = "Trying to initiate IKSolverVR with invalid bone references.";
				return false;
			}
			if (this.leftArm.wristToPalmAxis == Vector3.zero)
			{
				message = "Left arm 'Wrist To Palm Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the wrist towards the palm. If the arrow points away from the palm, axis must be negative.";
				return false;
			}
			if (this.rightArm.wristToPalmAxis == Vector3.zero)
			{
				message = "Right arm 'Wrist To Palm Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the wrist towards the palm. If the arrow points away from the palm, axis must be negative.";
				return false;
			}
			if (this.leftArm.palmToThumbAxis == Vector3.zero)
			{
				message = "Left arm 'Palm To Thumb Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the palm towards the thumb. If the arrow points away from the thumb, axis must be negative.";
				return false;
			}
			if (this.rightArm.palmToThumbAxis == Vector3.zero)
			{
				message = "Right arm 'Palm To Thumb Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the palm towards the thumb. If the arrow points away from the thumb, axis must be negative.";
				return false;
			}
			return true;
		}

		// Token: 0x06000758 RID: 1880 RVA: 0x000263E8 File Offset: 0x000247E8
		private Vector3 GetNormal(Transform[] transforms)
		{
			Vector3 vector = Vector3.zero;
			Vector3 vector2 = Vector3.zero;
			for (int i = 0; i < transforms.Length; i++)
			{
				vector2 += transforms[i].position;
			}
			vector2 /= (float)transforms.Length;
			for (int j = 0; j < transforms.Length - 1; j++)
			{
				vector += Vector3.Cross(transforms[j].position - vector2, transforms[j + 1].position - vector2).normalized;
			}
			return vector;
		}

		// Token: 0x06000759 RID: 1881 RVA: 0x0002647C File Offset: 0x0002487C
		private Vector3 GuessWristToPalmAxis(Transform hand, Transform forearm)
		{
			Vector3 vector = forearm.position - hand.position;
			Vector3 vector2 = AxisTools.ToVector3(AxisTools.GetAxisToDirection(hand, vector));
			if (Vector3.Dot(vector, hand.rotation * vector2) > 0f)
			{
				vector2 = -vector2;
			}
			return vector2;
		}

		// Token: 0x0600075A RID: 1882 RVA: 0x000264CC File Offset: 0x000248CC
		private Vector3 GuessPalmToThumbAxis(Transform hand, Transform forearm)
		{
			if (hand.childCount == 0)
			{
				Debug.LogWarning("Hand " + hand.name + " does not have any fingers, VRIK can not guess the hand bone's orientation.", hand);
				return Vector3.zero;
			}
			float num = float.PositiveInfinity;
			int index = 0;
			for (int i = 0; i < hand.childCount; i++)
			{
				float num2 = Vector3.SqrMagnitude(hand.GetChild(i).position - hand.position);
				if (num2 < num)
				{
					num = num2;
					index = i;
				}
			}
			Vector3 lhs = Vector3.Cross(hand.position - forearm.position, hand.GetChild(index).position - hand.position);
			Vector3 vector = Vector3.Cross(lhs, hand.position - forearm.position);
			Vector3 vector2 = AxisTools.ToVector3(AxisTools.GetAxisToDirection(hand, vector));
			if (Vector3.Dot(vector, hand.rotation * vector2) < 0f)
			{
				vector2 = -vector2;
			}
			return vector2;
		}

		// Token: 0x0600075B RID: 1883 RVA: 0x000265D0 File Offset: 0x000249D0
		private static Keyframe[] GetSineKeyframes(float mag)
		{
			Keyframe[] array = new Keyframe[3];
			array[0].time = 0f;
			array[0].value = 0f;
			array[1].time = 0.5f;
			array[1].value = mag;
			array[2].time = 1f;
			array[2].value = 0f;
			return array;
		}

		// Token: 0x0600075C RID: 1884 RVA: 0x00026648 File Offset: 0x00024A48
		private void UpdateSolverTransforms()
		{
			for (int i = 0; i < this.solverTransforms.Length; i++)
			{
				if (this.solverTransforms[i] != null)
				{
					this.readPositions[i] = this.solverTransforms[i].position;
					this.readRotations[i] = this.solverTransforms[i].rotation;
				}
			}
		}

		// Token: 0x0600075D RID: 1885 RVA: 0x000266BD File Offset: 0x00024ABD
		protected override void OnInitiate()
		{
			this.UpdateSolverTransforms();
			this.Read(this.readPositions, this.readRotations, this.hasNeck, this.hasShoulders, this.hasToes);
		}

		// Token: 0x0600075E RID: 1886 RVA: 0x000266EC File Offset: 0x00024AEC
		protected override void OnUpdate()
		{
			if (this.IKPositionWeight > 0f)
			{
				this.UpdateSolverTransforms();
				this.Read(this.readPositions, this.readRotations, this.hasNeck, this.hasShoulders, this.hasToes);
				this.Solve();
				this.Write();
				this.WriteTransforms();
			}
		}

		// Token: 0x0600075F RID: 1887 RVA: 0x00026748 File Offset: 0x00024B48
		private void WriteTransforms()
		{
			for (int i = 0; i < this.solverTransforms.Length; i++)
			{
				if (this.solverTransforms[i] != null)
				{
					if (i < 2)
					{
						this.solverTransforms[i].position = V3Tools.Lerp(this.solverTransforms[i].position, this.GetPosition(i), this.IKPositionWeight);
					}
					this.solverTransforms[i].rotation = QuaTools.Lerp(this.solverTransforms[i].rotation, this.GetRotation(i), this.IKPositionWeight);
				}
			}
		}

		// Token: 0x06000760 RID: 1888 RVA: 0x000267E0 File Offset: 0x00024BE0
		private void Read(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes)
		{
			if (this.rootBone == null)
			{
				this.rootBone = new IKSolverVR.VirtualBone(positions[0], rotations[0]);
			}
			else
			{
				this.rootBone.Read(positions[0], rotations[0]);
			}
			this.spine.Read(positions, rotations, hasNeck, hasShoulders, hasToes, 0, 1);
			this.leftArm.Read(positions, rotations, hasNeck, hasShoulders, hasToes, 3, 6);
			this.rightArm.Read(positions, rotations, hasNeck, hasShoulders, hasToes, 3, 10);
			this.leftLeg.Read(positions, rotations, hasNeck, hasShoulders, hasToes, 1, 14);
			this.rightLeg.Read(positions, rotations, hasNeck, hasShoulders, hasToes, 1, 18);
			for (int i = 0; i < rotations.Length; i++)
			{
				if (i < 2)
				{
					this.solvedPositions[i] = positions[i];
				}
				this.solvedRotations[i] = rotations[i];
			}
			if (!base.initiated)
			{
				this.legs = new IKSolverVR.Leg[]
				{
					this.leftLeg,
					this.rightLeg
				};
				this.arms = new IKSolverVR.Arm[]
				{
					this.leftArm,
					this.rightArm
				};
				this.locomotion.Initiate(positions, rotations, hasToes);
				this.raycastOriginPelvis = this.spine.pelvis.readPosition;
				this.spine.faceDirection = this.readRotations[0] * Vector3.forward;
			}
		}

		// Token: 0x06000761 RID: 1889 RVA: 0x00026994 File Offset: 0x00024D94
		private void Solve()
		{
			this.spine.PreSolve();
			foreach (IKSolverVR.Arm arm in this.arms)
			{
				arm.PreSolve();
			}
			foreach (IKSolverVR.Leg leg in this.legs)
			{
				leg.PreSolve();
			}
			foreach (IKSolverVR.Arm arm2 in this.arms)
			{
				arm2.ApplyOffsets();
			}
			this.spine.ApplyOffsets();
			this.spine.Solve(this.rootBone, this.legs, this.arms);
			if (this.spine.pelvisPositionWeight > 0f && this.plantFeet)
			{
				Warning.Log("If VRIK 'Pelvis Position Weight' is > 0, 'Plant Feet' should be disabled to improve performance and stability.", this.root, false);
			}
			if (this.locomotion.weight > 0f)
			{
				Vector3 a = Vector3.zero;
				Vector3 a2 = Vector3.zero;
				Quaternion identity = Quaternion.identity;
				Quaternion identity2 = Quaternion.identity;
				float num = 0f;
				float num2 = 0f;
				float d = 0f;
				float d2 = 0f;
				this.locomotion.Solve(this.rootBone, this.spine, this.leftLeg, this.rightLeg, this.leftArm, this.rightArm, out a, out a2, out identity, out identity2, out num, out num2, out d, out d2);
				a += this.root.up * num;
				a2 += this.root.up * num2;
				this.leftLeg.footPositionOffset += (a - this.leftLeg.lastBone.solverPosition) * this.IKPositionWeight * (1f - this.leftLeg.positionWeight) * this.locomotion.weight;
				this.rightLeg.footPositionOffset += (a2 - this.rightLeg.lastBone.solverPosition) * this.IKPositionWeight * (1f - this.rightLeg.positionWeight) * this.locomotion.weight;
				this.leftLeg.heelPositionOffset += this.root.up * d * this.locomotion.weight;
				this.rightLeg.heelPositionOffset += this.root.up * d2 * this.locomotion.weight;
				Quaternion quaternion = QuaTools.FromToRotation(this.leftLeg.lastBone.solverRotation, identity);
				Quaternion quaternion2 = QuaTools.FromToRotation(this.rightLeg.lastBone.solverRotation, identity2);
				quaternion = Quaternion.Lerp(Quaternion.identity, quaternion, this.IKPositionWeight * (1f - this.leftLeg.rotationWeight) * this.locomotion.weight);
				quaternion2 = Quaternion.Lerp(Quaternion.identity, quaternion2, this.IKPositionWeight * (1f - this.rightLeg.rotationWeight) * this.locomotion.weight);
				this.leftLeg.footRotationOffset = quaternion * this.leftLeg.footRotationOffset;
				this.rightLeg.footRotationOffset = quaternion2 * this.rightLeg.footRotationOffset;
				Vector3 vector = Vector3.Lerp(this.leftLeg.position + this.leftLeg.footPositionOffset, this.rightLeg.position + this.rightLeg.footPositionOffset, 0.5f);
				vector.y = this.rootBone.solverPosition.y;
				this.rootVelocity += (vector - this.rootBone.solverPosition) * Time.deltaTime * 10f;
				this.rootBone.solverPosition += this.rootVelocity * Time.deltaTime * 2f * this.locomotion.weight;
				this.rootBone.solverPosition = Vector3.Lerp(this.rootBone.solverPosition, vector, Time.deltaTime * this.locomotion.rootSpeed * this.locomotion.weight);
				float d3 = num + num2;
				this.bodyOffset = Vector3.Lerp(this.bodyOffset, this.root.up * d3, Time.deltaTime * 3f);
				this.bodyOffset = Vector3.Lerp(Vector3.zero, this.bodyOffset, this.locomotion.weight);
			}
			foreach (IKSolverVR.Leg leg2 in this.legs)
			{
				leg2.ApplyOffsets();
			}
			if (!this.plantFeet)
			{
				this.spine.InverseTranslateToHead(this.legs, false, false, this.bodyOffset, 1f);
				foreach (IKSolverVR.Leg leg3 in this.legs)
				{
					leg3.TranslateRoot(this.spine.pelvis.solverPosition, this.spine.pelvis.solverRotation);
				}
				foreach (IKSolverVR.Leg leg4 in this.legs)
				{
					leg4.Solve();
				}
			}
			else
			{
				for (int num3 = 0; num3 < 2; num3++)
				{
					this.spine.InverseTranslateToHead(this.legs, true, num3 == 0, this.bodyOffset, 1f);
					foreach (IKSolverVR.Leg leg5 in this.legs)
					{
						leg5.TranslateRoot(this.spine.pelvis.solverPosition, this.spine.pelvis.solverRotation);
					}
					foreach (IKSolverVR.Leg leg6 in this.legs)
					{
						leg6.Solve();
					}
				}
			}
			for (int num6 = 0; num6 < this.arms.Length; num6++)
			{
				this.arms[num6].TranslateRoot(this.spine.chest.solverPosition, this.spine.chest.solverRotation);
				this.arms[num6].Solve(num6 == 0);
			}
			this.spine.ResetOffsets();
			foreach (IKSolverVR.Leg leg7 in this.legs)
			{
				leg7.ResetOffsets();
			}
			foreach (IKSolverVR.Arm arm3 in this.arms)
			{
				arm3.ResetOffsets();
			}
			this.spine.pelvisPositionOffset += this.GetPelvisOffset();
			this.spine.chestPositionOffset += this.spine.pelvisPositionOffset;
			this.Write();
		}

		// Token: 0x06000762 RID: 1890 RVA: 0x0002713F File Offset: 0x0002553F
		private Vector3 GetPosition(int index)
		{
			if (index >= 2)
			{
				Debug.LogError("Can only get root and pelvis positions from IKSolverVR. GetPosition index out of range.");
			}
			return this.solvedPositions[index];
		}

		// Token: 0x06000763 RID: 1891 RVA: 0x00027163 File Offset: 0x00025563
		private Quaternion GetRotation(int index)
		{
			return this.solvedRotations[index];
		}

		// Token: 0x1700007A RID: 122
		// (get) Token: 0x06000764 RID: 1892 RVA: 0x00027176 File Offset: 0x00025576
		// (set) Token: 0x06000765 RID: 1893 RVA: 0x0002717E File Offset: 0x0002557E
		[HideInInspector]
		public IKSolverVR.VirtualBone rootBone { get; private set; }

		// Token: 0x06000766 RID: 1894 RVA: 0x00027188 File Offset: 0x00025588
		private void Write()
		{
			this.solvedPositions[0] = this.rootBone.solverPosition;
			this.solvedRotations[0] = this.rootBone.solverRotation;
			this.spine.Write(ref this.solvedPositions, ref this.solvedRotations);
			foreach (IKSolverVR.Leg leg in this.legs)
			{
				leg.Write(ref this.solvedPositions, ref this.solvedRotations);
			}
			foreach (IKSolverVR.Arm arm in this.arms)
			{
				arm.Write(ref this.solvedPositions, ref this.solvedRotations);
			}
		}

		// Token: 0x06000767 RID: 1895 RVA: 0x00027250 File Offset: 0x00025650
		private Vector3 GetPelvisOffset()
		{
			if (this.locomotion.weight <= 0f)
			{
				return Vector3.zero;
			}
			if (this.locomotion.blockingLayers == -1)
			{
				return Vector3.zero;
			}
			Vector3 vector = this.raycastOriginPelvis;
			vector.y = this.spine.pelvis.solverPosition.y;
			Vector3 vector2 = this.spine.pelvis.readPosition;
			vector2.y = this.spine.pelvis.solverPosition.y;
			Vector3 direction = vector2 - vector;
			RaycastHit raycastHit;
			if (this.locomotion.raycastRadius <= 0f)
			{
				if (Physics.Raycast(vector, direction, out raycastHit, direction.magnitude * 1.1f, this.locomotion.blockingLayers))
				{
					vector2 = raycastHit.point;
				}
			}
			else if (Physics.SphereCast(vector, this.locomotion.raycastRadius * 1.1f, direction, out raycastHit, direction.magnitude, this.locomotion.blockingLayers))
			{
				vector2 = vector + direction.normalized * raycastHit.distance / 1.1f;
			}
			Vector3 a = this.spine.pelvis.solverPosition;
			direction = a - vector2;
			if (this.locomotion.raycastRadius <= 0f)
			{
				if (Physics.Raycast(vector2, direction, out raycastHit, direction.magnitude, this.locomotion.blockingLayers))
				{
					a = raycastHit.point;
				}
			}
			else if (Physics.SphereCast(vector2, this.locomotion.raycastRadius, direction, out raycastHit, direction.magnitude, this.locomotion.blockingLayers))
			{
				a = vector2 + direction.normalized * raycastHit.distance;
			}
			this.lastOffset = Vector3.Lerp(this.lastOffset, Vector3.zero, Time.deltaTime * 3f);
			a += Vector3.ClampMagnitude(this.lastOffset, 0.75f);
			a.y = this.spine.pelvis.solverPosition.y;
			this.lastOffset = Vector3.Lerp(this.lastOffset, a - this.spine.pelvis.solverPosition, Time.deltaTime * 15f);
			return this.lastOffset;
		}

		// Token: 0x04000416 RID: 1046
		private Transform[] solverTransforms = new Transform[0];

		// Token: 0x04000417 RID: 1047
		private bool hasNeck;

		// Token: 0x04000418 RID: 1048
		private bool hasShoulders;

		// Token: 0x04000419 RID: 1049
		private bool hasToes;

		// Token: 0x0400041A RID: 1050
		private Vector3[] readPositions = new Vector3[0];

		// Token: 0x0400041B RID: 1051
		private Quaternion[] readRotations = new Quaternion[0];

		// Token: 0x0400041C RID: 1052
		private Vector3[] solvedPositions = new Vector3[2];

		// Token: 0x0400041D RID: 1053
		private Quaternion[] solvedRotations = new Quaternion[22];

		// Token: 0x0400041E RID: 1054
		private Vector3 defaultPelvisLocalPosition;

		// Token: 0x0400041F RID: 1055
		private Quaternion[] defaultLocalRotations = new Quaternion[21];

		// Token: 0x04000420 RID: 1056
		private Vector3 rootV;

		// Token: 0x04000421 RID: 1057
		private Vector3 rootVelocity;

		// Token: 0x04000422 RID: 1058
		private Vector3 bodyOffset;

		// Token: 0x04000423 RID: 1059
		[Tooltip("If true, will keep the toes planted even if head target is out of reach.")]
		public bool plantFeet = true;

		// Token: 0x04000425 RID: 1061
		[Tooltip("The spine solver.")]
		public IKSolverVR.Spine spine = new IKSolverVR.Spine();

		// Token: 0x04000426 RID: 1062
		[Tooltip("The left arm solver.")]
		public IKSolverVR.Arm leftArm = new IKSolverVR.Arm();

		// Token: 0x04000427 RID: 1063
		[Tooltip("The right arm solver.")]
		public IKSolverVR.Arm rightArm = new IKSolverVR.Arm();

		// Token: 0x04000428 RID: 1064
		[Tooltip("The left leg solver.")]
		public IKSolverVR.Leg leftLeg = new IKSolverVR.Leg();

		// Token: 0x04000429 RID: 1065
		[Tooltip("The right leg solver.")]
		public IKSolverVR.Leg rightLeg = new IKSolverVR.Leg();

		// Token: 0x0400042A RID: 1066
		[Tooltip("The procedural locomotion solver.")]
		public IKSolverVR.Locomotion locomotion = new IKSolverVR.Locomotion();

		// Token: 0x0400042B RID: 1067
		private IKSolverVR.Leg[] legs = new IKSolverVR.Leg[2];

		// Token: 0x0400042C RID: 1068
		private IKSolverVR.Arm[] arms = new IKSolverVR.Arm[2];

		// Token: 0x0400042D RID: 1069
		private Vector3 headPosition;

		// Token: 0x0400042E RID: 1070
		private Vector3 headDeltaPosition;

		// Token: 0x0400042F RID: 1071
		private Vector3 raycastOriginPelvis;

		// Token: 0x04000430 RID: 1072
		private Vector3 lastOffset;

		// Token: 0x04000431 RID: 1073
		private Vector3 debugPos1;

		// Token: 0x04000432 RID: 1074
		private Vector3 debugPos2;

		// Token: 0x04000433 RID: 1075
		private Vector3 debugPos3;

		// Token: 0x04000434 RID: 1076
		private Vector3 debugPos4;

		// Token: 0x02000181 RID: 385
		[Serializable]
		public class Arm : IKSolverVR.BodyPart
		{
			// Token: 0x1700007B RID: 123
			// (get) Token: 0x06000769 RID: 1897 RVA: 0x000277E0 File Offset: 0x00025BE0
			// (set) Token: 0x0600076A RID: 1898 RVA: 0x000277E8 File Offset: 0x00025BE8
			public Vector3 position { get; private set; }

			// Token: 0x1700007C RID: 124
			// (get) Token: 0x0600076B RID: 1899 RVA: 0x000277F1 File Offset: 0x00025BF1
			// (set) Token: 0x0600076C RID: 1900 RVA: 0x000277F9 File Offset: 0x00025BF9
			public Quaternion rotation { get; private set; }

			// Token: 0x1700007D RID: 125
			// (get) Token: 0x0600076D RID: 1901 RVA: 0x00027802 File Offset: 0x00025C02
			private IKSolverVR.VirtualBone shoulder
			{
				get
				{
					return this.bones[0];
				}
			}

			// Token: 0x1700007E RID: 126
			// (get) Token: 0x0600076E RID: 1902 RVA: 0x0002780C File Offset: 0x00025C0C
			private IKSolverVR.VirtualBone upperArm
			{
				get
				{
					return this.bones[1];
				}
			}

			// Token: 0x1700007F RID: 127
			// (get) Token: 0x0600076F RID: 1903 RVA: 0x00027816 File Offset: 0x00025C16
			private IKSolverVR.VirtualBone forearm
			{
				get
				{
					return this.bones[2];
				}
			}

			// Token: 0x17000080 RID: 128
			// (get) Token: 0x06000770 RID: 1904 RVA: 0x00027820 File Offset: 0x00025C20
			private IKSolverVR.VirtualBone hand
			{
				get
				{
					return this.bones[3];
				}
			}

			// Token: 0x06000771 RID: 1905 RVA: 0x0002782C File Offset: 0x00025C2C
			protected override void OnRead(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes, int rootIndex, int index)
			{
				Vector3 position = positions[index];
				Quaternion rotation = rotations[index];
				Vector3 position2 = positions[index + 1];
				Quaternion rotation2 = rotations[index + 1];
				Vector3 position3 = positions[index + 2];
				Quaternion rotation3 = rotations[index + 2];
				Vector3 vector = positions[index + 3];
				Quaternion quaternion = rotations[index + 3];
				if (!this.initiated)
				{
					this.IKPosition = vector;
					this.IKRotation = quaternion;
					this.hasShoulder = hasShoulders;
					this.bones = new IKSolverVR.VirtualBone[(!this.hasShoulder) ? 3 : 4];
					if (this.hasShoulder)
					{
						this.bones[0] = new IKSolverVR.VirtualBone(position, rotation);
						this.bones[1] = new IKSolverVR.VirtualBone(position2, rotation2);
						this.bones[2] = new IKSolverVR.VirtualBone(position3, rotation3);
						this.bones[3] = new IKSolverVR.VirtualBone(vector, quaternion);
					}
					else
					{
						this.bones[0] = new IKSolverVR.VirtualBone(position2, rotation2);
						this.bones[1] = new IKSolverVR.VirtualBone(position3, rotation3);
						this.bones[2] = new IKSolverVR.VirtualBone(vector, quaternion);
					}
					this.chestForwardAxis = Quaternion.Inverse(this.rootRotation) * (rotations[0] * Vector3.forward);
					this.chestUpAxis = Quaternion.Inverse(this.rootRotation) * (rotations[0] * Vector3.up);
				}
				if (this.hasShoulder)
				{
					this.bones[0].Read(position, rotation);
					this.bones[1].Read(position2, rotation2);
					this.bones[2].Read(position3, rotation3);
					this.bones[3].Read(vector, quaternion);
				}
				else
				{
					this.bones[0].Read(position2, rotation2);
					this.bones[1].Read(position3, rotation3);
					this.bones[2].Read(vector, quaternion);
				}
			}

			// Token: 0x06000772 RID: 1906 RVA: 0x00027A54 File Offset: 0x00025E54
			public override void PreSolve()
			{
				if (this.target != null)
				{
					this.IKPosition = this.target.position;
					this.IKRotation = this.target.rotation;
				}
				this.position = V3Tools.Lerp(this.hand.solverPosition, this.IKPosition, this.positionWeight);
				this.rotation = QuaTools.Lerp(this.hand.solverRotation, this.IKRotation, this.rotationWeight);
				this.shoulder.axis = this.shoulder.axis.normalized;
				this.forearmRelToUpperArm = Quaternion.Inverse(this.upperArm.solverRotation) * this.forearm.solverRotation;
			}

			// Token: 0x06000773 RID: 1907 RVA: 0x00027B19 File Offset: 0x00025F19
			public override void ApplyOffsets()
			{
				this.position += this.handPositionOffset;
			}

			// Token: 0x06000774 RID: 1908 RVA: 0x00027B34 File Offset: 0x00025F34
			public void Solve(bool isLeft)
			{
				this.chestRotation = Quaternion.LookRotation(this.rootRotation * this.chestForwardAxis, this.rootRotation * this.chestUpAxis);
				this.chestForward = this.chestRotation * Vector3.forward;
				this.chestUp = this.chestRotation * Vector3.up;
				if (this.hasShoulder && this.shoulderRotationWeight > 0f)
				{
					IKSolverVR.Arm.ShoulderRotationMode shoulderRotationMode = this.shoulderRotationMode;
					if (shoulderRotationMode != IKSolverVR.Arm.ShoulderRotationMode.YawPitch)
					{
						if (shoulderRotationMode == IKSolverVR.Arm.ShoulderRotationMode.FromTo)
						{
							Quaternion solverRotation = this.shoulder.solverRotation;
							Quaternion quaternion = Quaternion.FromToRotation((this.upperArm.solverPosition - this.shoulder.solverPosition).normalized + this.chestForward, this.position - this.shoulder.solverPosition);
							quaternion = Quaternion.Slerp(Quaternion.identity, quaternion, 0.5f * this.shoulderRotationWeight);
							IKSolverVR.VirtualBone.RotateBy(this.bones, quaternion);
							IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 0, 2, 3, this.position, Vector3.Cross(this.forearm.solverPosition - this.shoulder.solverPosition, this.hand.solverPosition - this.shoulder.solverPosition), 0.5f * this.shoulderRotationWeight);
							IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 1, 2, 3, this.position, this.GetBendNormal(this.position - this.upperArm.solverPosition), 1f);
							Quaternion rotation = Quaternion.Inverse(Quaternion.LookRotation(this.chestUp, this.chestForward));
							Vector3 vector = rotation * (solverRotation * this.shoulder.axis);
							Vector3 vector2 = rotation * (this.shoulder.solverRotation * this.shoulder.axis);
							float current = Mathf.Atan2(vector.x, vector.z) * 57.29578f;
							float num = Mathf.Atan2(vector2.x, vector2.z) * 57.29578f;
							float num2 = Mathf.DeltaAngle(current, num);
							if (isLeft)
							{
								num2 = -num2;
							}
							num2 = Mathf.Clamp(num2 * 2f, 0f, 180f);
							this.shoulder.solverRotation = Quaternion.AngleAxis(num2, this.shoulder.solverRotation * ((!isLeft) ? (-this.shoulder.axis) : this.shoulder.axis)) * this.shoulder.solverRotation;
							this.upperArm.solverRotation = Quaternion.AngleAxis(num2, this.upperArm.solverRotation * ((!isLeft) ? (-this.upperArm.axis) : this.upperArm.axis)) * this.upperArm.solverRotation;
						}
					}
					else
					{
						Vector3 point = (this.position - this.shoulder.solverPosition).normalized;
						float num3 = (!isLeft) ? -45f : 45f;
						Quaternion lhs = Quaternion.AngleAxis(((!isLeft) ? 90f : -90f) + num3, this.chestUp);
						Quaternion quaternion2 = lhs * this.chestRotation;
						Vector3 lhs2 = Quaternion.Inverse(quaternion2) * point;
						float num4 = Mathf.Atan2(lhs2.x, lhs2.z) * 57.29578f;
						float num5 = Vector3.Dot(lhs2, Vector3.up);
						num5 = 1f - Mathf.Abs(num5);
						num4 *= num5;
						num4 -= num3;
						num4 = this.DamperValue(num4, -45f - num3, 45f - num3, 0.7f);
						Quaternion rotation2 = Quaternion.AngleAxis(num4, Vector3.up);
						Vector3 fromDirection = Quaternion.Inverse(quaternion2) * (this.shoulder.solverRotation * this.shoulder.axis);
						Vector3 toDirection = rotation2 * Vector3.forward;
						Quaternion rhs = Quaternion.FromToRotation(fromDirection, toDirection);
						Quaternion lhs3 = Quaternion.AngleAxis((!isLeft) ? 90f : -90f, this.chestUp);
						quaternion2 = lhs3 * this.chestRotation;
						quaternion2 = Quaternion.AngleAxis((!isLeft) ? 30f : -30f, this.chestForward) * quaternion2;
						point = this.position - (this.shoulder.solverPosition + this.chestRotation * ((!isLeft) ? Vector3.left : Vector3.right) * base.mag);
						lhs2 = Quaternion.Inverse(quaternion2) * point;
						float num6 = Mathf.Atan2(lhs2.y, lhs2.z) * 57.29578f;
						num6 -= -30f;
						num6 = this.DamperValue(num6, -15f, 75f, 1f);
						Quaternion lhs4 = Quaternion.AngleAxis(-num6, quaternion2 * Vector3.right);
						Quaternion quaternion3 = lhs4 * rhs;
						if (this.shoulderRotationWeight < 1f)
						{
							quaternion3 = Quaternion.Lerp(Quaternion.identity, quaternion3, this.shoulderRotationWeight);
						}
						IKSolverVR.VirtualBone.RotateBy(this.bones, quaternion3);
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 1, 2, 3, this.position, this.GetBendNormal(this.position - this.upperArm.solverPosition), 1f);
						float angle = Mathf.Clamp(num6 * 2f, 0f, 180f);
						this.shoulder.solverRotation = Quaternion.AngleAxis(angle, this.shoulder.solverRotation * ((!isLeft) ? (-this.shoulder.axis) : this.shoulder.axis)) * this.shoulder.solverRotation;
						this.upperArm.solverRotation = Quaternion.AngleAxis(angle, this.upperArm.solverRotation * ((!isLeft) ? (-this.upperArm.axis) : this.upperArm.axis)) * this.upperArm.solverRotation;
					}
				}
				else
				{
					IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 1, 2, 3, this.position, this.GetBendNormal(this.position - this.upperArm.solverPosition), 1f);
				}
				Quaternion quaternion4 = this.upperArm.solverRotation * this.forearmRelToUpperArm;
				Quaternion lhs5 = Quaternion.FromToRotation(quaternion4 * this.forearm.axis, this.hand.solverPosition - this.forearm.solverPosition);
				base.RotateTo(this.forearm, lhs5 * quaternion4, 1f);
				this.hand.solverRotation = this.rotation;
			}

			// Token: 0x06000775 RID: 1909 RVA: 0x0002826A File Offset: 0x0002666A
			public override void ResetOffsets()
			{
				this.handPositionOffset = Vector3.zero;
			}

			// Token: 0x06000776 RID: 1910 RVA: 0x00028278 File Offset: 0x00026678
			public override void Write(ref Vector3[] solvedPositions, ref Quaternion[] solvedRotations)
			{
				if (this.hasShoulder)
				{
					solvedRotations[this.index] = this.shoulder.solverRotation;
				}
				solvedRotations[this.index + 1] = this.upperArm.solverRotation;
				solvedRotations[this.index + 2] = this.forearm.solverRotation;
				solvedRotations[this.index + 3] = this.hand.solverRotation;
			}

			// Token: 0x06000777 RID: 1911 RVA: 0x0002830C File Offset: 0x0002670C
			private float DamperValue(float value, float min, float max, float weight = 1f)
			{
				float num = max - min;
				if (weight < 1f)
				{
					float num2 = max - num * 0.5f;
					float num3 = value - num2;
					num3 *= 0.5f;
					value = num2 + num3;
				}
				value -= min;
				float t = Mathf.Clamp(value / num, 0f, 1f);
				float t2 = Interp.Float(t, InterpolationMode.InOutQuintic);
				return Mathf.Lerp(min, max, t2);
			}

			// Token: 0x06000778 RID: 1912 RVA: 0x00028370 File Offset: 0x00026770
			private Vector3 GetBendNormal(Vector3 dir)
			{
				if (this.bendGoal != null)
				{
					this.bendDirection = this.bendGoal.position - this.bones[0].solverPosition;
				}
				if (this.bendGoalWeight < 1f)
				{
					Vector3 vector = this.bones[0].solverRotation * this.bones[0].axis;
					Vector3 fromDirection = Vector3.down;
					Vector3 toDirection = Quaternion.Inverse(this.chestRotation) * dir.normalized + Vector3.forward;
					Quaternion rotation = Quaternion.FromToRotation(fromDirection, toDirection);
					Vector3 vector2 = rotation * Vector3.back;
					fromDirection = Quaternion.Inverse(this.chestRotation) * vector;
					toDirection = Quaternion.Inverse(this.chestRotation) * dir;
					rotation = Quaternion.FromToRotation(fromDirection, toDirection);
					vector2 = rotation * vector2;
					vector2 = this.chestRotation * vector2;
					vector2 += vector;
					vector2 -= this.rotation * this.wristToPalmAxis;
					vector2 -= this.rotation * this.palmToThumbAxis * 0.5f;
					if (this.bendGoalWeight > 0f)
					{
						vector2 = Vector3.Slerp(vector2, this.bendDirection, this.bendGoalWeight);
					}
					if (this.swivelOffset != 0f)
					{
						vector2 = Quaternion.AngleAxis(this.swivelOffset, -dir) * vector2;
					}
					return Vector3.Cross(vector2, dir);
				}
				return Vector3.Cross(this.bendDirection, dir);
			}

			// Token: 0x06000779 RID: 1913 RVA: 0x0002850F File Offset: 0x0002690F
			private void Visualize(IKSolverVR.VirtualBone bone1, IKSolverVR.VirtualBone bone2, IKSolverVR.VirtualBone bone3, Color color)
			{
				Debug.DrawLine(bone1.solverPosition, bone2.solverPosition, color);
				Debug.DrawLine(bone2.solverPosition, bone3.solverPosition, color);
			}

			// Token: 0x04000435 RID: 1077
			[Tooltip("The hand target")]
			public Transform target;

			// Token: 0x04000436 RID: 1078
			[Tooltip("The elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.")]
			public Transform bendGoal;

			// Token: 0x04000437 RID: 1079
			[Tooltip("Positional weight of the hand target.")]
			[Range(0f, 1f)]
			public float positionWeight = 1f;

			// Token: 0x04000438 RID: 1080
			[Tooltip("Rotational weight of the hand target")]
			[Range(0f, 1f)]
			public float rotationWeight = 1f;

			// Token: 0x04000439 RID: 1081
			[Tooltip("Different techniques for shoulder bone rotation.")]
			public IKSolverVR.Arm.ShoulderRotationMode shoulderRotationMode;

			// Token: 0x0400043A RID: 1082
			[Tooltip("The weight of shoulder rotation")]
			[Range(0f, 1f)]
			public float shoulderRotationWeight = 1f;

			// Token: 0x0400043B RID: 1083
			[Tooltip("If greater than 0, will bend the elbow towards the 'Bend Goal' Transform.")]
			[Range(0f, 1f)]
			public float bendGoalWeight;

			// Token: 0x0400043C RID: 1084
			[Tooltip("Angular offset of the elbow bending direction.")]
			[Range(-180f, 180f)]
			public float swivelOffset;

			// Token: 0x0400043D RID: 1085
			[Tooltip("Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation.")]
			public Vector3 wristToPalmAxis = Vector3.zero;

			// Token: 0x0400043E RID: 1086
			[Tooltip("Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation.")]
			public Vector3 palmToThumbAxis = Vector3.zero;

			// Token: 0x0400043F RID: 1087
			[HideInInspector]
			public Vector3 IKPosition;

			// Token: 0x04000440 RID: 1088
			[HideInInspector]
			public Quaternion IKRotation = Quaternion.identity;

			// Token: 0x04000441 RID: 1089
			[HideInInspector]
			public Vector3 bendDirection = Vector3.back;

			// Token: 0x04000442 RID: 1090
			[HideInInspector]
			public Vector3 handPositionOffset;

			// Token: 0x04000445 RID: 1093
			private bool hasShoulder;

			// Token: 0x04000446 RID: 1094
			private Vector3 chestForwardAxis;

			// Token: 0x04000447 RID: 1095
			private Vector3 chestUpAxis;

			// Token: 0x04000448 RID: 1096
			private Quaternion chestRotation;

			// Token: 0x04000449 RID: 1097
			private Vector3 chestForward;

			// Token: 0x0400044A RID: 1098
			private Vector3 chestUp;

			// Token: 0x0400044B RID: 1099
			private Quaternion forearmRelToUpperArm;

			// Token: 0x0400044C RID: 1100
			private const float yawOffsetAngle = 45f;

			// Token: 0x0400044D RID: 1101
			private const float pitchOffsetAngle = -30f;

			// Token: 0x02000182 RID: 386
			[Serializable]
			public enum ShoulderRotationMode
			{
				// Token: 0x0400044F RID: 1103
				YawPitch,
				// Token: 0x04000450 RID: 1104
				FromTo
			}
		}

		// Token: 0x02000183 RID: 387
		[Serializable]
		public abstract class BodyPart
		{
			// Token: 0x0600077B RID: 1915
			protected abstract void OnRead(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes, int rootIndex, int index);

			// Token: 0x0600077C RID: 1916
			public abstract void PreSolve();

			// Token: 0x0600077D RID: 1917
			public abstract void Write(ref Vector3[] solvedPositions, ref Quaternion[] solvedRotations);

			// Token: 0x0600077E RID: 1918
			public abstract void ApplyOffsets();

			// Token: 0x0600077F RID: 1919
			public abstract void ResetOffsets();

			// Token: 0x17000081 RID: 129
			// (get) Token: 0x06000780 RID: 1920 RVA: 0x000274F6 File Offset: 0x000258F6
			// (set) Token: 0x06000781 RID: 1921 RVA: 0x000274FE File Offset: 0x000258FE
			public float sqrMag { get; private set; }

			// Token: 0x17000082 RID: 130
			// (get) Token: 0x06000782 RID: 1922 RVA: 0x00027507 File Offset: 0x00025907
			// (set) Token: 0x06000783 RID: 1923 RVA: 0x0002750F File Offset: 0x0002590F
			public float mag { get; private set; }

			// Token: 0x06000784 RID: 1924 RVA: 0x00027518 File Offset: 0x00025918
			public void Read(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes, int rootIndex, int index)
			{
				this.index = index;
				this.rootPosition = positions[rootIndex];
				this.rootRotation = rotations[rootIndex];
				this.OnRead(positions, rotations, hasNeck, hasShoulders, hasToes, rootIndex, index);
				this.mag = IKSolverVR.VirtualBone.PreSolve(ref this.bones);
				this.sqrMag = this.mag * this.mag;
				this.initiated = true;
			}

			// Token: 0x06000785 RID: 1925 RVA: 0x00027590 File Offset: 0x00025990
			public void MovePosition(Vector3 position)
			{
				Vector3 b = position - this.bones[0].solverPosition;
				foreach (IKSolverVR.VirtualBone virtualBone in this.bones)
				{
					virtualBone.solverPosition += b;
				}
			}

			// Token: 0x06000786 RID: 1926 RVA: 0x000275E4 File Offset: 0x000259E4
			public void MoveRotation(Quaternion rotation)
			{
				Quaternion rotation2 = QuaTools.FromToRotation(this.bones[0].solverRotation, rotation);
				IKSolverVR.VirtualBone.RotateAroundPoint(this.bones, 0, this.bones[0].solverPosition, rotation2);
			}

			// Token: 0x06000787 RID: 1927 RVA: 0x0002761F File Offset: 0x00025A1F
			public void Translate(Vector3 position, Quaternion rotation)
			{
				this.MovePosition(position);
				this.MoveRotation(rotation);
			}

			// Token: 0x06000788 RID: 1928 RVA: 0x00027630 File Offset: 0x00025A30
			public void TranslateRoot(Vector3 newRootPos, Quaternion newRootRot)
			{
				Vector3 b = newRootPos - this.rootPosition;
				this.rootPosition = newRootPos;
				foreach (IKSolverVR.VirtualBone virtualBone in this.bones)
				{
					virtualBone.solverPosition += b;
				}
				Quaternion rotation = QuaTools.FromToRotation(this.rootRotation, newRootRot);
				this.rootRotation = newRootRot;
				IKSolverVR.VirtualBone.RotateAroundPoint(this.bones, 0, newRootPos, rotation);
			}

			// Token: 0x06000789 RID: 1929 RVA: 0x000276A8 File Offset: 0x00025AA8
			public void RotateTo(IKSolverVR.VirtualBone bone, Quaternion rotation, float weight = 1f)
			{
				if (weight <= 0f)
				{
					return;
				}
				Quaternion quaternion = QuaTools.FromToRotation(bone.solverRotation, rotation);
				if (weight < 1f)
				{
					quaternion = Quaternion.Slerp(Quaternion.identity, quaternion, weight);
				}
				for (int i = 0; i < this.bones.Length; i++)
				{
					if (this.bones[i] == bone)
					{
						IKSolverVR.VirtualBone.RotateAroundPoint(this.bones, i, this.bones[i].solverPosition, quaternion);
						return;
					}
				}
			}

			// Token: 0x0600078A RID: 1930 RVA: 0x00027728 File Offset: 0x00025B28
			public void Visualize(Color color)
			{
				for (int i = 0; i < this.bones.Length - 1; i++)
				{
					Debug.DrawLine(this.bones[i].solverPosition, this.bones[i + 1].solverPosition, color);
				}
			}

			// Token: 0x0600078B RID: 1931 RVA: 0x00027772 File Offset: 0x00025B72
			public void Visualize()
			{
				this.Visualize(Color.white);
			}

			// Token: 0x04000453 RID: 1107
			[HideInInspector]
			public IKSolverVR.VirtualBone[] bones = new IKSolverVR.VirtualBone[0];

			// Token: 0x04000454 RID: 1108
			protected bool initiated;

			// Token: 0x04000455 RID: 1109
			protected Vector3 rootPosition;

			// Token: 0x04000456 RID: 1110
			protected Quaternion rootRotation = Quaternion.identity;

			// Token: 0x04000457 RID: 1111
			protected int index = -1;
		}

		// Token: 0x02000184 RID: 388
		[Serializable]
		public class Footstep
		{
			// Token: 0x0600078C RID: 1932 RVA: 0x00028538 File Offset: 0x00026938
			public Footstep(Quaternion rootRotation, Vector3 footPosition, Quaternion footRotation, Vector3 characterSpaceOffset)
			{
				this.characterSpaceOffset = characterSpaceOffset;
				this.Reset(rootRotation, footPosition, footRotation);
			}

			// Token: 0x17000083 RID: 131
			// (get) Token: 0x0600078D RID: 1933 RVA: 0x00028588 File Offset: 0x00026988
			// (set) Token: 0x0600078E RID: 1934 RVA: 0x00028590 File Offset: 0x00026990
			public Vector3 position { get; private set; }

			// Token: 0x17000084 RID: 132
			// (get) Token: 0x0600078F RID: 1935 RVA: 0x00028599 File Offset: 0x00026999
			// (set) Token: 0x06000790 RID: 1936 RVA: 0x000285A1 File Offset: 0x000269A1
			public Quaternion rotation { get; private set; }

			// Token: 0x17000085 RID: 133
			// (get) Token: 0x06000791 RID: 1937 RVA: 0x000285AA File Offset: 0x000269AA
			// (set) Token: 0x06000792 RID: 1938 RVA: 0x000285B2 File Offset: 0x000269B2
			public Quaternion stepToRootRot { get; private set; }

			// Token: 0x17000086 RID: 134
			// (get) Token: 0x06000793 RID: 1939 RVA: 0x000285BB File Offset: 0x000269BB
			public bool isStepping
			{
				get
				{
					return this.stepProgress < 1f;
				}
			}

			// Token: 0x17000087 RID: 135
			// (get) Token: 0x06000794 RID: 1940 RVA: 0x000285CA File Offset: 0x000269CA
			// (set) Token: 0x06000795 RID: 1941 RVA: 0x000285D2 File Offset: 0x000269D2
			public float stepProgress { get; private set; }

			// Token: 0x17000088 RID: 136
			// (get) Token: 0x06000796 RID: 1942 RVA: 0x000285DB File Offset: 0x000269DB
			// (set) Token: 0x06000797 RID: 1943 RVA: 0x000285E3 File Offset: 0x000269E3
			public Vector3 stepFrom { get; private set; }

			// Token: 0x06000798 RID: 1944 RVA: 0x000285EC File Offset: 0x000269EC
			public void Reset(Quaternion rootRotation, Vector3 footPosition, Quaternion footRotation)
			{
				this.position = footPosition;
				this.rotation = footRotation;
				this.stepFrom = this.position;
				this.stepTo = this.position;
				this.stepFromRot = this.rotation;
				this.stepToRot = this.rotation;
				this.stepToRootRot = rootRotation;
				this.stepProgress = 1f;
				this.footRelativeToRoot = Quaternion.Inverse(rootRotation) * this.rotation;
			}

			// Token: 0x06000799 RID: 1945 RVA: 0x00028660 File Offset: 0x00026A60
			public void StepTo(Vector3 p, Quaternion rootRotation)
			{
				this.stepFrom = this.position;
				this.stepTo = p;
				this.stepFromRot = this.rotation;
				this.stepToRootRot = rootRotation;
				this.stepToRot = rootRotation * this.footRelativeToRoot;
				this.stepProgress = 0f;
			}

			// Token: 0x0600079A RID: 1946 RVA: 0x000286B0 File Offset: 0x00026AB0
			public void Update(InterpolationMode interpolation)
			{
				if (!this.isStepping)
				{
					return;
				}
				this.stepProgress = Mathf.MoveTowards(this.stepProgress, 1f, Time.deltaTime * this.stepSpeed);
				float t = Interp.Float(this.stepProgress, interpolation);
				this.position = Vector3.Lerp(this.stepFrom, this.stepTo, t);
				this.rotation = Quaternion.Lerp(this.stepFromRot, this.stepToRot, t);
			}

			// Token: 0x04000458 RID: 1112
			public float stepSpeed = 3f;

			// Token: 0x04000459 RID: 1113
			public Vector3 characterSpaceOffset;

			// Token: 0x0400045F RID: 1119
			public Vector3 stepTo;

			// Token: 0x04000460 RID: 1120
			private Quaternion stepFromRot = Quaternion.identity;

			// Token: 0x04000461 RID: 1121
			private Quaternion stepToRot = Quaternion.identity;

			// Token: 0x04000462 RID: 1122
			private Quaternion footRelativeToRoot = Quaternion.identity;
		}

		// Token: 0x02000185 RID: 389
		[Serializable]
		public class Leg : IKSolverVR.BodyPart
		{
			// Token: 0x17000089 RID: 137
			// (get) Token: 0x0600079C RID: 1948 RVA: 0x0002873B File Offset: 0x00026B3B
			// (set) Token: 0x0600079D RID: 1949 RVA: 0x00028743 File Offset: 0x00026B43
			public Vector3 IKPosition { get; private set; }

			// Token: 0x1700008A RID: 138
			// (get) Token: 0x0600079E RID: 1950 RVA: 0x0002874C File Offset: 0x00026B4C
			// (set) Token: 0x0600079F RID: 1951 RVA: 0x00028754 File Offset: 0x00026B54
			public Quaternion IKRotation { get; private set; }

			// Token: 0x1700008B RID: 139
			// (get) Token: 0x060007A0 RID: 1952 RVA: 0x0002875D File Offset: 0x00026B5D
			// (set) Token: 0x060007A1 RID: 1953 RVA: 0x00028765 File Offset: 0x00026B65
			public Vector3 position { get; private set; }

			// Token: 0x1700008C RID: 140
			// (get) Token: 0x060007A2 RID: 1954 RVA: 0x0002876E File Offset: 0x00026B6E
			// (set) Token: 0x060007A3 RID: 1955 RVA: 0x00028776 File Offset: 0x00026B76
			public Quaternion rotation { get; private set; }

			// Token: 0x1700008D RID: 141
			// (get) Token: 0x060007A4 RID: 1956 RVA: 0x0002877F File Offset: 0x00026B7F
			// (set) Token: 0x060007A5 RID: 1957 RVA: 0x00028787 File Offset: 0x00026B87
			public bool hasToes { get; private set; }

			// Token: 0x1700008E RID: 142
			// (get) Token: 0x060007A6 RID: 1958 RVA: 0x00028790 File Offset: 0x00026B90
			public IKSolverVR.VirtualBone thigh
			{
				get
				{
					return this.bones[0];
				}
			}

			// Token: 0x1700008F RID: 143
			// (get) Token: 0x060007A7 RID: 1959 RVA: 0x0002879A File Offset: 0x00026B9A
			private IKSolverVR.VirtualBone calf
			{
				get
				{
					return this.bones[1];
				}
			}

			// Token: 0x17000090 RID: 144
			// (get) Token: 0x060007A8 RID: 1960 RVA: 0x000287A4 File Offset: 0x00026BA4
			private IKSolverVR.VirtualBone foot
			{
				get
				{
					return this.bones[2];
				}
			}

			// Token: 0x17000091 RID: 145
			// (get) Token: 0x060007A9 RID: 1961 RVA: 0x000287AE File Offset: 0x00026BAE
			private IKSolverVR.VirtualBone toes
			{
				get
				{
					return this.bones[3];
				}
			}

			// Token: 0x17000092 RID: 146
			// (get) Token: 0x060007AA RID: 1962 RVA: 0x000287B8 File Offset: 0x00026BB8
			public IKSolverVR.VirtualBone lastBone
			{
				get
				{
					return this.bones[this.bones.Length - 1];
				}
			}

			// Token: 0x17000093 RID: 147
			// (get) Token: 0x060007AB RID: 1963 RVA: 0x000287CB File Offset: 0x00026BCB
			// (set) Token: 0x060007AC RID: 1964 RVA: 0x000287D3 File Offset: 0x00026BD3
			public Vector3 thighRelativeToPelvis { get; private set; }

			// Token: 0x060007AD RID: 1965 RVA: 0x000287DC File Offset: 0x00026BDC
			protected override void OnRead(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes, int rootIndex, int index)
			{
				Vector3 position = positions[index];
				Quaternion rotation = rotations[index];
				Vector3 position2 = positions[index + 1];
				Quaternion rotation2 = rotations[index + 1];
				Vector3 vector = positions[index + 2];
				Quaternion quaternion = rotations[index + 2];
				Vector3 vector2 = positions[index + 3];
				Quaternion quaternion2 = rotations[index + 3];
				if (!this.initiated)
				{
					this.hasToes = hasToes;
					this.bones = new IKSolverVR.VirtualBone[(!hasToes) ? 3 : 4];
					if (hasToes)
					{
						this.bones[0] = new IKSolverVR.VirtualBone(position, rotation);
						this.bones[1] = new IKSolverVR.VirtualBone(position2, rotation2);
						this.bones[2] = new IKSolverVR.VirtualBone(vector, quaternion);
						this.bones[3] = new IKSolverVR.VirtualBone(vector2, quaternion2);
						this.IKPosition = vector2;
						this.IKRotation = quaternion2;
					}
					else
					{
						this.bones[0] = new IKSolverVR.VirtualBone(position, rotation);
						this.bones[1] = new IKSolverVR.VirtualBone(position2, rotation2);
						this.bones[2] = new IKSolverVR.VirtualBone(vector, quaternion);
						this.IKPosition = vector;
						this.IKRotation = quaternion;
					}
				}
				if (hasToes)
				{
					this.bones[0].Read(position, rotation);
					this.bones[1].Read(position2, rotation2);
					this.bones[2].Read(vector, quaternion);
					this.bones[3].Read(vector2, quaternion2);
				}
				else
				{
					this.bones[0].Read(position, rotation);
					this.bones[1].Read(position2, rotation2);
					this.bones[2].Read(vector, quaternion);
				}
			}

			// Token: 0x060007AE RID: 1966 RVA: 0x000289AC File Offset: 0x00026DAC
			public override void PreSolve()
			{
				if (this.target != null)
				{
					this.IKPosition = this.target.position;
					this.IKRotation = this.target.rotation;
				}
				this.footPosition = this.foot.solverPosition;
				this.footRotation = this.foot.solverRotation;
				this.position = this.lastBone.solverPosition;
				this.rotation = this.lastBone.solverRotation;
				if (this.rotationWeight > 0f)
				{
					this.ApplyRotationOffset(QuaTools.FromToRotation(this.rotation, this.IKRotation), this.rotationWeight);
				}
				if (this.positionWeight > 0f)
				{
					this.ApplyPositionOffset(this.IKPosition - this.position, this.positionWeight);
				}
				this.thighRelativeToPelvis = Quaternion.Inverse(this.rootRotation) * (this.thigh.solverPosition - this.rootPosition);
				this.calfRelToThigh = Quaternion.Inverse(this.thigh.solverRotation) * this.calf.solverRotation;
				this.bendNormal = Vector3.Cross(this.calf.solverPosition - this.thigh.solverPosition, this.foot.solverPosition - this.calf.solverPosition);
			}

			// Token: 0x060007AF RID: 1967 RVA: 0x00028B20 File Offset: 0x00026F20
			public override void ApplyOffsets()
			{
				this.ApplyPositionOffset(this.footPositionOffset, 1f);
				this.ApplyRotationOffset(this.footRotationOffset, 1f);
				Quaternion quaternion = Quaternion.FromToRotation(this.footPosition - this.position, this.footPosition + this.heelPositionOffset - this.position);
				this.footPosition = this.position + quaternion * (this.footPosition - this.position);
				this.footRotation = quaternion * this.footRotation;
				float num = 0f;
				if (this.bendGoal != null && this.bendGoalWeight > 0f)
				{
					Vector3 point = Vector3.Cross(this.bendGoal.position - this.thigh.solverPosition, this.foot.solverPosition - this.thigh.solverPosition);
					Quaternion rotation = Quaternion.LookRotation(this.bendNormal, this.thigh.solverPosition - this.foot.solverPosition);
					Vector3 vector = Quaternion.Inverse(rotation) * point;
					num = Mathf.Atan2(vector.x, vector.z) * 57.29578f * this.bendGoalWeight;
				}
				float num2 = this.swivelOffset + num;
				if (num2 != 0f)
				{
					this.bendNormal = Quaternion.AngleAxis(num2, this.thigh.solverPosition - this.lastBone.solverPosition) * this.bendNormal;
					this.thigh.solverRotation = Quaternion.AngleAxis(-num2, this.thigh.solverRotation * this.thigh.axis) * this.thigh.solverRotation;
				}
			}

			// Token: 0x060007B0 RID: 1968 RVA: 0x00028CFC File Offset: 0x000270FC
			private void ApplyPositionOffset(Vector3 offset, float weight)
			{
				if (weight <= 0f)
				{
					return;
				}
				offset *= weight;
				this.footPosition += offset;
				this.position += offset;
			}

			// Token: 0x060007B1 RID: 1969 RVA: 0x00028D38 File Offset: 0x00027138
			private void ApplyRotationOffset(Quaternion offset, float weight)
			{
				if (weight <= 0f)
				{
					return;
				}
				if (weight < 1f)
				{
					offset = Quaternion.Lerp(Quaternion.identity, offset, weight);
				}
				this.footRotation = offset * this.footRotation;
				this.rotation = offset * this.rotation;
				this.bendNormal = offset * this.bendNormal;
				this.footPosition = this.position + offset * (this.footPosition - this.position);
			}

			// Token: 0x060007B2 RID: 1970 RVA: 0x00028DC8 File Offset: 0x000271C8
			public void Solve()
			{
				IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 0, 1, 2, this.footPosition, this.bendNormal, 1f);
				base.RotateTo(this.foot, this.footRotation, 1f);
				if (!this.hasToes)
				{
					return;
				}
				Vector3 vector = Vector3.Cross(this.foot.solverPosition - this.thigh.solverPosition, this.toes.solverPosition - this.foot.solverPosition);
				IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 0, 2, 3, this.position, vector, 1f);
				Quaternion quaternion = this.thigh.solverRotation * this.calfRelToThigh;
				Quaternion lhs = Quaternion.FromToRotation(quaternion * this.calf.axis, this.foot.solverPosition - this.calf.solverPosition);
				base.RotateTo(this.calf, lhs * quaternion, 1f);
				this.toes.solverRotation = this.rotation;
			}

			// Token: 0x060007B3 RID: 1971 RVA: 0x00028EE0 File Offset: 0x000272E0
			public override void Write(ref Vector3[] solvedPositions, ref Quaternion[] solvedRotations)
			{
				solvedRotations[this.index] = this.thigh.solverRotation;
				solvedRotations[this.index + 1] = this.calf.solverRotation;
				solvedRotations[this.index + 2] = this.foot.solverRotation;
				if (this.hasToes)
				{
					solvedRotations[this.index + 3] = this.toes.solverRotation;
				}
			}

			// Token: 0x060007B4 RID: 1972 RVA: 0x00028F72 File Offset: 0x00027372
			public override void ResetOffsets()
			{
				this.footPositionOffset = Vector3.zero;
				this.footRotationOffset = Quaternion.identity;
				this.heelPositionOffset = Vector3.zero;
			}

			// Token: 0x04000463 RID: 1123
			[Tooltip("The toe/foot target.")]
			public Transform target;

			// Token: 0x04000464 RID: 1124
			[Tooltip("The knee will be bent towards this Transform if 'Bend Goal Weight' > 0.")]
			public Transform bendGoal;

			// Token: 0x04000465 RID: 1125
			[Tooltip("Positional weight of the toe/foot target.")]
			[Range(0f, 1f)]
			public float positionWeight;

			// Token: 0x04000466 RID: 1126
			[Tooltip("Rotational weight of the toe/foot target.")]
			[Range(0f, 1f)]
			public float rotationWeight;

			// Token: 0x04000467 RID: 1127
			[Tooltip("If greater than 0, will bend the knee towards the 'Bend Goal' Transform.")]
			[Range(0f, 1f)]
			public float bendGoalWeight;

			// Token: 0x04000468 RID: 1128
			[Tooltip("Angular offset of the knee bending direction.")]
			[Range(-180f, 180f)]
			public float swivelOffset;

			// Token: 0x0400046B RID: 1131
			[HideInInspector]
			public Vector3 footPositionOffset;

			// Token: 0x0400046C RID: 1132
			[HideInInspector]
			public Vector3 heelPositionOffset;

			// Token: 0x0400046D RID: 1133
			[HideInInspector]
			public Quaternion footRotationOffset = Quaternion.identity;

			// Token: 0x0400046E RID: 1134
			[HideInInspector]
			public float currentMag;

			// Token: 0x04000473 RID: 1139
			private Vector3 footPosition;

			// Token: 0x04000474 RID: 1140
			private Quaternion footRotation;

			// Token: 0x04000475 RID: 1141
			private Vector3 bendNormal;

			// Token: 0x04000476 RID: 1142
			private Quaternion calfRelToThigh;
		}

		// Token: 0x02000186 RID: 390
		[Serializable]
		public class Locomotion
		{
			// Token: 0x17000094 RID: 148
			// (get) Token: 0x060007B6 RID: 1974 RVA: 0x00029042 File Offset: 0x00027442
			// (set) Token: 0x060007B7 RID: 1975 RVA: 0x0002904A File Offset: 0x0002744A
			public Vector3 centerOfMass { get; private set; }

			// Token: 0x060007B8 RID: 1976 RVA: 0x00029054 File Offset: 0x00027454
			public void Initiate(Vector3[] positions, Quaternion[] rotations, bool hasToes)
			{
				this.leftFootIndex = ((!hasToes) ? 16 : 17);
				this.rightFootIndex = ((!hasToes) ? 20 : 21);
				this.footsteps = new IKSolverVR.Footstep[]
				{
					new IKSolverVR.Footstep(rotations[0], positions[this.leftFootIndex], rotations[this.leftFootIndex], this.footDistance * Vector3.left),
					new IKSolverVR.Footstep(rotations[0], positions[this.rightFootIndex], rotations[this.rightFootIndex], this.footDistance * Vector3.right)
				};
			}

			// Token: 0x060007B9 RID: 1977 RVA: 0x00029124 File Offset: 0x00027524
			public void Reset(Vector3[] positions, Quaternion[] rotations)
			{
				this.lastComPosition = Vector3.Lerp(positions[1], positions[5], 0.25f) + rotations[0] * this.offset;
				this.comVelocity = Vector3.zero;
				this.footsteps[0].Reset(rotations[0], positions[this.leftFootIndex], rotations[this.leftFootIndex]);
				this.footsteps[1].Reset(rotations[0], positions[this.rightFootIndex], rotations[this.rightFootIndex]);
			}

			// Token: 0x060007BA RID: 1978 RVA: 0x000291F8 File Offset: 0x000275F8
			public void Solve(IKSolverVR.VirtualBone rootBone, IKSolverVR.Spine spine, IKSolverVR.Leg leftLeg, IKSolverVR.Leg rightLeg, IKSolverVR.Arm leftArm, IKSolverVR.Arm rightArm, out Vector3 leftFootPosition, out Vector3 rightFootPosition, out Quaternion leftFootRotation, out Quaternion rightFootRotation, out float leftFootOffset, out float rightFootOffset, out float leftHeelOffset, out float rightHeelOffset)
			{
				if (this.weight <= 0f)
				{
					leftFootPosition = Vector3.zero;
					rightFootPosition = Vector3.zero;
					leftFootRotation = Quaternion.identity;
					rightFootRotation = Quaternion.identity;
					leftFootOffset = 0f;
					rightFootOffset = 0f;
					leftHeelOffset = 0f;
					rightHeelOffset = 0f;
					return;
				}
				Vector3 vector = spine.pelvis.solverPosition + spine.pelvis.solverRotation * leftLeg.thighRelativeToPelvis;
				Vector3 vector2 = spine.pelvis.solverPosition + spine.pelvis.solverRotation * rightLeg.thighRelativeToPelvis;
				this.footsteps[0].characterSpaceOffset = this.footDistance * Vector3.left;
				this.footsteps[1].characterSpaceOffset = this.footDistance * Vector3.right;
				Vector3 faceDirection = spine.faceDirection;
				faceDirection.y = 0f;
				Quaternion quaternion = Quaternion.LookRotation(faceDirection);
				float num = 1f;
				float num2 = 1f;
				float num3 = 0.2f;
				float d = num + num2 + 2f * num3;
				this.centerOfMass = Vector3.zero;
				this.centerOfMass += spine.pelvis.solverPosition * num;
				this.centerOfMass += spine.head.solverPosition * num2;
				this.centerOfMass += leftArm.position * num3;
				this.centerOfMass += rightArm.position * num3;
				this.centerOfMass /= d;
				this.centerOfMass += rootBone.solverRotation * this.offset;
				this.comVelocity = (this.centerOfMass - this.lastComPosition) / Time.deltaTime;
				this.lastComPosition = this.centerOfMass;
				this.comVelocity = Vector3.ClampMagnitude(this.comVelocity, this.maxVelocity) * this.velocityFactor;
				Vector3 a = this.centerOfMass + this.comVelocity;
				Vector3 a2 = new Vector3(spine.pelvis.solverPosition.x, rootBone.solverPosition.y, spine.pelvis.solverPosition.z);
				Vector3 a3 = new Vector3(a.x, rootBone.solverPosition.y, a.z);
				Vector3 b = Vector3.Lerp(this.footsteps[0].position, this.footsteps[1].position, 0.5f);
				Vector3 from = a - b;
				float num4 = Vector3.Angle(from, rootBone.solverRotation * Vector3.up) * this.comAngleMlp;
				for (int i = 0; i < this.footsteps.Length; i++)
				{
					if (this.footsteps[i].isStepping)
					{
						Vector3 vector3 = a3 + rootBone.solverRotation * this.footsteps[i].characterSpaceOffset;
						if (!this.StepBlocked(this.footsteps[i].stepFrom, vector3, rootBone.solverPosition))
						{
							this.footsteps[i].stepTo = Vector3.Lerp(this.footsteps[i].stepTo, vector3, Time.deltaTime * 8f);
						}
					}
				}
				if (this.CanStep())
				{
					int num5 = -1;
					float num6 = float.NegativeInfinity;
					for (int j = 0; j < this.footsteps.Length; j++)
					{
						if (!this.footsteps[j].isStepping)
						{
							Vector3 vector4 = a3 + rootBone.solverRotation * this.footsteps[j].characterSpaceOffset;
							float num7 = (j != 0) ? rightLeg.mag : leftLeg.mag;
							Vector3 b2 = (j != 0) ? vector2 : vector;
							float num8 = Vector3.Distance(this.footsteps[j].position, b2);
							bool flag = false;
							if (num8 >= num7 * this.maxLegStretch)
							{
								vector4 = a2 + rootBone.solverRotation * this.footsteps[j].characterSpaceOffset;
								flag = true;
							}
							bool flag2 = false;
							for (int k = 0; k < this.footsteps.Length; k++)
							{
								if (k != j && !flag)
								{
									if (Vector3.Distance(this.footsteps[j].position, this.footsteps[k].position) >= 0.25f || (this.footsteps[j].position - vector4).sqrMagnitude >= (this.footsteps[k].position - vector4).sqrMagnitude)
									{
										flag2 = IKSolverVR.Locomotion.GetLineSphereCollision(this.footsteps[j].position, vector4, this.footsteps[k].position, 0.25f);
									}
									if (flag2)
									{
										break;
									}
								}
							}
							float num9 = Quaternion.Angle(quaternion, this.footsteps[j].stepToRootRot);
							if (!flag2 || num9 > this.angleThreshold)
							{
								float num10 = Vector3.Distance(this.footsteps[j].position, vector4);
								float num11 = Mathf.Lerp(this.stepThreshold, this.stepThreshold * 0.1f, num4 * 0.015f);
								if (flag)
								{
									num11 *= 0.5f;
								}
								if (j == 0)
								{
									num11 *= 0.9f;
								}
								if (!this.StepBlocked(this.footsteps[j].position, vector4, rootBone.solverPosition) && (num10 > num11 || num9 > this.angleThreshold))
								{
									float num12 = 0f;
									num12 -= num10;
									if (num12 > num6)
									{
										num5 = j;
										num6 = num12;
									}
								}
							}
						}
					}
					if (num5 != -1)
					{
						Vector3 p = a3 + rootBone.solverRotation * this.footsteps[num5].characterSpaceOffset;
						this.footsteps[num5].stepSpeed = UnityEngine.Random.Range(this.stepSpeed, this.stepSpeed * 1.5f);
						this.footsteps[num5].StepTo(p, quaternion);
					}
				}
				foreach (IKSolverVR.Footstep footstep in this.footsteps)
				{
					footstep.Update(this.stepInterpolation);
				}
				leftFootPosition = this.footsteps[0].position;
				rightFootPosition = this.footsteps[1].position;
				leftFootPosition.y = leftLeg.lastBone.readPosition.y;
				rightFootPosition.y = rightLeg.lastBone.readPosition.y;
				leftFootOffset = this.stepHeight.Evaluate(this.footsteps[0].stepProgress);
				rightFootOffset = this.stepHeight.Evaluate(this.footsteps[1].stepProgress);
				leftHeelOffset = this.heelHeight.Evaluate(this.footsteps[0].stepProgress);
				rightHeelOffset = this.heelHeight.Evaluate(this.footsteps[1].stepProgress);
				leftFootRotation = this.footsteps[0].rotation;
				rightFootRotation = this.footsteps[1].rotation;
			}

			// Token: 0x060007BB RID: 1979 RVA: 0x000299AC File Offset: 0x00027DAC
			private bool StepBlocked(Vector3 fromPosition, Vector3 toPosition, Vector3 rootPosition)
			{
				if (this.blockingLayers == -1 || !this.blockingEnabled)
				{
					return false;
				}
				Vector3 vector = fromPosition;
				vector.y = rootPosition.y + this.raycastHeight + this.raycastRadius;
				Vector3 direction = toPosition - vector;
				direction.y = 0f;
				RaycastHit raycastHit;
				if (this.raycastRadius <= 0f)
				{
					return Physics.Raycast(vector, direction, out raycastHit, direction.magnitude, this.blockingLayers);
				}
				return Physics.SphereCast(vector, this.raycastRadius, direction, out raycastHit, direction.magnitude, this.blockingLayers);
			}

			// Token: 0x060007BC RID: 1980 RVA: 0x00029A58 File Offset: 0x00027E58
			private bool CanStep()
			{
				foreach (IKSolverVR.Footstep footstep in this.footsteps)
				{
					if (footstep.isStepping && footstep.stepProgress < 0.8f)
					{
						return false;
					}
				}
				return true;
			}

			// Token: 0x060007BD RID: 1981 RVA: 0x00029AA4 File Offset: 0x00027EA4
			private static bool GetLineSphereCollision(Vector3 lineStart, Vector3 lineEnd, Vector3 sphereCenter, float sphereRadius)
			{
				Vector3 forward = lineEnd - lineStart;
				Vector3 vector = sphereCenter - lineStart;
				float magnitude = vector.magnitude;
				float num = magnitude - sphereRadius;
				if (num > forward.magnitude)
				{
					return false;
				}
				Quaternion rotation = Quaternion.LookRotation(forward, vector);
				Vector3 vector2 = Quaternion.Inverse(rotation) * vector;
				if (vector2.z < 0f)
				{
					return num < 0f;
				}
				return vector2.y - sphereRadius < 0f;
			}

			// Token: 0x04000477 RID: 1143
			[Tooltip("Used for blending in/out of procedural locomotion.")]
			[Range(0f, 1f)]
			public float weight = 1f;

			// Token: 0x04000478 RID: 1144
			[Tooltip("Tries to maintain this distance between the legs.")]
			public float footDistance = 0.3f;

			// Token: 0x04000479 RID: 1145
			[Tooltip("Makes a step only if step target position is at least this far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past the 'Angle Threshold'.")]
			public float stepThreshold = 0.4f;

			// Token: 0x0400047A RID: 1146
			[Tooltip("Makes a step only if step target position is at least 'Step Threshold' far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past this value.")]
			public float angleThreshold = 60f;

			// Token: 0x0400047B RID: 1147
			[Tooltip("Multiplies angle of the center of mass - center of pressure vector. Larger value makes the character step sooner if losing balance.")]
			public float comAngleMlp = 1f;

			// Token: 0x0400047C RID: 1148
			[Tooltip("Maximum magnitude of head/hand target velocity used in prediction.")]
			public float maxVelocity = 0.4f;

			// Token: 0x0400047D RID: 1149
			[Tooltip("The amount of head/hand target velocity prediction.")]
			public float velocityFactor = 0.4f;

			// Token: 0x0400047E RID: 1150
			[Tooltip("How much can a leg be extended before it is forced to step to another position? 1 means fully stretched.")]
			[Range(0.9f, 1f)]
			public float maxLegStretch = 1f;

			// Token: 0x0400047F RID: 1151
			[Tooltip("The speed of lerping the root of the character towards the horizontal mid-point of the footsteps.")]
			public float rootSpeed = 20f;

			// Token: 0x04000480 RID: 1152
			[Tooltip("The speed of steps.")]
			public float stepSpeed = 3f;

			// Token: 0x04000481 RID: 1153
			[Tooltip("The height of the foot by normalized step progress (0 - 1).")]
			public AnimationCurve stepHeight;

			// Token: 0x04000482 RID: 1154
			[Tooltip("The height offset of the heel by normalized step progress (0 - 1).")]
			public AnimationCurve heelHeight;

			// Token: 0x04000483 RID: 1155
			[Tooltip("Interpolation mode of the step.")]
			public InterpolationMode stepInterpolation = InterpolationMode.InOutSine;

			// Token: 0x04000484 RID: 1156
			[Tooltip("Offset for the approximated center of mass.")]
			public Vector3 offset;

			// Token: 0x04000485 RID: 1157
			[HideInInspector]
			public bool blockingEnabled;

			// Token: 0x04000486 RID: 1158
			[HideInInspector]
			public LayerMask blockingLayers;

			// Token: 0x04000487 RID: 1159
			[HideInInspector]
			public float raycastRadius = 0.2f;

			// Token: 0x04000488 RID: 1160
			[HideInInspector]
			public float raycastHeight = 0.2f;

			// Token: 0x0400048A RID: 1162
			private IKSolverVR.Footstep[] footsteps = new IKSolverVR.Footstep[0];

			// Token: 0x0400048B RID: 1163
			private Vector3 lastComPosition;

			// Token: 0x0400048C RID: 1164
			private Vector3 comVelocity;

			// Token: 0x0400048D RID: 1165
			private int leftFootIndex;

			// Token: 0x0400048E RID: 1166
			private int rightFootIndex;
		}

		// Token: 0x02000187 RID: 391
		[Serializable]
		public class Spine : IKSolverVR.BodyPart
		{
			// Token: 0x17000095 RID: 149
			// (get) Token: 0x060007BF RID: 1983 RVA: 0x00029BF9 File Offset: 0x00027FF9
			// (set) Token: 0x060007C0 RID: 1984 RVA: 0x00029C01 File Offset: 0x00028001
			public Vector3 IKPositionHead { get; private set; }

			// Token: 0x17000096 RID: 150
			// (get) Token: 0x060007C1 RID: 1985 RVA: 0x00029C0A File Offset: 0x0002800A
			// (set) Token: 0x060007C2 RID: 1986 RVA: 0x00029C12 File Offset: 0x00028012
			public Quaternion IKRotationHead { get; private set; }

			// Token: 0x17000097 RID: 151
			// (get) Token: 0x060007C3 RID: 1987 RVA: 0x00029C1B File Offset: 0x0002801B
			// (set) Token: 0x060007C4 RID: 1988 RVA: 0x00029C23 File Offset: 0x00028023
			public Vector3 IKPositionPelvis { get; private set; }

			// Token: 0x17000098 RID: 152
			// (get) Token: 0x060007C5 RID: 1989 RVA: 0x00029C2C File Offset: 0x0002802C
			public IKSolverVR.VirtualBone pelvis
			{
				get
				{
					return this.bones[0];
				}
			}

			// Token: 0x17000099 RID: 153
			// (get) Token: 0x060007C6 RID: 1990 RVA: 0x00029C36 File Offset: 0x00028036
			public IKSolverVR.VirtualBone firstSpineBone
			{
				get
				{
					return this.bones[1];
				}
			}

			// Token: 0x1700009A RID: 154
			// (get) Token: 0x060007C7 RID: 1991 RVA: 0x00029C40 File Offset: 0x00028040
			public IKSolverVR.VirtualBone chest
			{
				get
				{
					return this.bones[2];
				}
			}

			// Token: 0x1700009B RID: 155
			// (get) Token: 0x060007C8 RID: 1992 RVA: 0x00029C4A File Offset: 0x0002804A
			private IKSolverVR.VirtualBone neck
			{
				get
				{
					return this.bones[3];
				}
			}

			// Token: 0x1700009C RID: 156
			// (get) Token: 0x060007C9 RID: 1993 RVA: 0x00029C54 File Offset: 0x00028054
			public IKSolverVR.VirtualBone head
			{
				get
				{
					return this.bones[this.headIndex];
				}
			}

			// Token: 0x1700009D RID: 157
			// (get) Token: 0x060007CA RID: 1994 RVA: 0x00029C63 File Offset: 0x00028063
			// (set) Token: 0x060007CB RID: 1995 RVA: 0x00029C6B File Offset: 0x0002806B
			public Quaternion anchorRotation { get; private set; }

			// Token: 0x060007CC RID: 1996 RVA: 0x00029C74 File Offset: 0x00028074
			protected override void OnRead(Vector3[] positions, Quaternion[] rotations, bool hasNeck, bool hasShoulders, bool hasToes, int rootIndex, int index)
			{
				Vector3 vector = positions[index];
				Quaternion quaternion = rotations[index];
				Vector3 position = positions[index + 1];
				Quaternion rotation = rotations[index + 1];
				Vector3 position2 = positions[index + 2];
				Quaternion quaternion2 = rotations[index + 2];
				Vector3 position3 = positions[index + 3];
				Quaternion rotation2 = rotations[index + 3];
				Vector3 vector2 = positions[index + 4];
				Quaternion quaternion3 = rotations[index + 4];
				if (!this.initiated)
				{
					this.hasNeck = hasNeck;
					this.headHeight = vector2.y - positions[0].y;
					this.bones = new IKSolverVR.VirtualBone[(!hasNeck) ? 4 : 5];
					this.headIndex = ((!hasNeck) ? 3 : 4);
					this.bones[0] = new IKSolverVR.VirtualBone(vector, quaternion);
					this.bones[1] = new IKSolverVR.VirtualBone(position, rotation);
					this.bones[2] = new IKSolverVR.VirtualBone(position2, quaternion2);
					if (hasNeck)
					{
						this.bones[3] = new IKSolverVR.VirtualBone(position3, rotation2);
					}
					this.bones[this.headIndex] = new IKSolverVR.VirtualBone(vector2, quaternion3);
					this.pelvisRotationOffset = Quaternion.identity;
					this.chestRotationOffset = Quaternion.identity;
					this.headRotationOffset = Quaternion.identity;
					this.anchorRelativeToHead = Quaternion.Inverse(quaternion3) * rotations[0];
					this.pelvisRelativeRotation = Quaternion.Inverse(quaternion3) * quaternion;
					this.chestRelativeRotation = Quaternion.Inverse(quaternion3) * quaternion2;
					this.faceDirection = rotations[0] * Vector3.forward;
					this.IKPositionHead = vector2;
					this.IKRotationHead = quaternion3;
					this.IKPositionPelvis = vector;
				}
				this.bones[0].Read(vector, quaternion);
				this.bones[1].Read(position, rotation);
				this.bones[2].Read(position2, quaternion2);
				if (hasNeck)
				{
					this.bones[3].Read(position3, rotation2);
				}
				this.bones[this.headIndex].Read(vector2, quaternion3);
			}

			// Token: 0x060007CD RID: 1997 RVA: 0x00029ECC File Offset: 0x000282CC
			public override void PreSolve()
			{
				if (this.headTarget != null)
				{
					this.IKPositionHead = this.headTarget.position;
					this.IKRotationHead = this.headTarget.rotation;
				}
				if (this.pelvisTarget != null)
				{
					this.IKPositionPelvis = this.pelvisTarget.position;
				}
				this.headPosition = V3Tools.Lerp(this.head.solverPosition, this.IKPositionHead, this.positionWeight);
				this.headRotation = QuaTools.Lerp(this.head.solverRotation, this.IKRotationHead, this.rotationWeight);
			}

			// Token: 0x060007CE RID: 1998 RVA: 0x00029F74 File Offset: 0x00028374
			public override void ApplyOffsets()
			{
				this.headPosition += this.headPositionOffset;
				this.headPosition.y = Math.Max(this.rootPosition.y + 0.8f, this.headPosition.y);
				this.headRotation = this.headRotationOffset * this.headRotation;
				this.headDeltaPosition = this.headPosition - this.head.solverPosition;
				this.pelvisDeltaRotation = QuaTools.FromToRotation(this.pelvis.solverRotation, this.headRotation * this.pelvisRelativeRotation);
				this.anchorRotation = this.headRotation * this.anchorRelativeToHead;
			}

			// Token: 0x060007CF RID: 1999 RVA: 0x0002A038 File Offset: 0x00028438
			private void CalculateChestTargetRotation(IKSolverVR.Arm[] arms)
			{
				this.chestTargetRotation = this.headRotation * this.chestRelativeRotation;
				this.AdjustChestByHands(ref this.chestTargetRotation, arms);
				this.AdjustChestByOffset(ref this.chestTargetRotation);
				this.faceDirection = Vector3.Cross(this.anchorRotation * Vector3.right, Vector3.up) + this.anchorRotation * Vector3.forward;
			}

			// Token: 0x060007D0 RID: 2000 RVA: 0x0002A0AC File Offset: 0x000284AC
			public void Solve(IKSolverVR.VirtualBone rootBone, IKSolverVR.Leg[] legs, IKSolverVR.Arm[] arms)
			{
				this.CalculateChestTargetRotation(arms);
				if (this.maxRootAngle < 180f)
				{
					Vector3 vector = Quaternion.Inverse(rootBone.solverRotation) * this.faceDirection;
					float num = Mathf.Atan2(vector.x, vector.z) * 57.29578f;
					float angle = 0f;
					float num2 = 25f;
					if (num > num2)
					{
						angle = num - num2;
					}
					if (num < -num2)
					{
						angle = num + num2;
					}
					rootBone.solverRotation = Quaternion.AngleAxis(angle, Vector3.up) * rootBone.solverRotation;
				}
				Vector3 solverPosition = this.pelvis.solverPosition;
				this.TranslatePelvis(legs, this.headDeltaPosition, this.pelvisDeltaRotation, 1f);
				IKSolverVR.VirtualBone.SolveFABRIK(this.bones, Vector3.Lerp(this.pelvis.solverPosition, solverPosition, this.maintainPelvisPosition) + this.pelvisPositionOffset - this.chestPositionOffset, this.headPosition - this.chestPositionOffset, 1f, 1f, 1, base.mag);
				this.Bend(this.bones, 0, 2, this.chestTargetRotation, this.chestClampWeight, false, this.chestRotationWeight);
				this.InverseTranslateToHead(legs, false, false, Vector3.zero, 1f);
				IKSolverVR.VirtualBone.SolveFABRIK(this.bones, Vector3.Lerp(this.pelvis.solverPosition, solverPosition, this.maintainPelvisPosition) + this.pelvisPositionOffset - this.chestPositionOffset, this.headPosition - this.chestPositionOffset, 1f, 1f, 1, base.mag);
				this.Bend(this.bones, 3, this.headIndex, this.headRotation, this.headClampWeight, true, 1f);
				this.SolvePelvis();
			}

			// Token: 0x060007D1 RID: 2001 RVA: 0x0002A27C File Offset: 0x0002867C
			private void SolvePelvis()
			{
				if (this.pelvisPositionWeight > 0f)
				{
					Quaternion solverRotation = this.head.solverRotation;
					Vector3 b = (this.IKPositionPelvis + this.pelvisPositionOffset - this.pelvis.solverPosition) * this.pelvisPositionWeight;
					foreach (IKSolverVR.VirtualBone virtualBone in this.bones)
					{
						virtualBone.solverPosition += b;
					}
					Vector3 bendNormal = this.anchorRotation * Vector3.right;
					if (this.hasNeck)
					{
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 0, 1, this.bones.Length - 1, this.headPosition, bendNormal, this.pelvisPositionWeight * 0.6f);
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 1, 2, this.bones.Length - 1, this.headPosition, bendNormal, this.pelvisPositionWeight * 0.6f);
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 2, 3, this.bones.Length - 1, this.headPosition, bendNormal, this.pelvisPositionWeight * 1f);
					}
					else
					{
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 0, 1, this.bones.Length - 1, this.headPosition, bendNormal, this.pelvisPositionWeight * 0.75f);
						IKSolverVR.VirtualBone.SolveTrigonometric(this.bones, 1, 2, this.bones.Length - 1, this.headPosition, bendNormal, this.pelvisPositionWeight * 1f);
					}
					this.head.solverRotation = solverRotation;
				}
			}

			// Token: 0x060007D2 RID: 2002 RVA: 0x0002A410 File Offset: 0x00028810
			public override void Write(ref Vector3[] solvedPositions, ref Quaternion[] solvedRotations)
			{
				solvedPositions[this.index] = this.bones[0].solverPosition;
				solvedRotations[this.index] = this.bones[0].solverRotation;
				solvedRotations[this.index + 1] = this.bones[1].solverRotation;
				solvedRotations[this.index + 2] = this.bones[2].solverRotation;
				if (this.hasNeck)
				{
					solvedRotations[this.index + 3] = this.bones[3].solverRotation;
				}
				solvedRotations[this.index + 4] = this.bones[this.headIndex].solverRotation;
			}

			// Token: 0x060007D3 RID: 2003 RVA: 0x0002A4F0 File Offset: 0x000288F0
			public override void ResetOffsets()
			{
				this.pelvisPositionOffset = Vector3.zero;
				this.chestPositionOffset = Vector3.zero;
				this.headPositionOffset = Vector3.zero;
				this.pelvisRotationOffset = Quaternion.identity;
				this.chestRotationOffset = Quaternion.identity;
				this.headRotationOffset = Quaternion.identity;
			}

			// Token: 0x060007D4 RID: 2004 RVA: 0x0002A53F File Offset: 0x0002893F
			private void AdjustChestByOffset(ref Quaternion chestTargetRotation)
			{
				chestTargetRotation = this.chestRotationOffset * chestTargetRotation;
			}

			// Token: 0x060007D5 RID: 2005 RVA: 0x0002A558 File Offset: 0x00028958
			private void AdjustChestByHands(ref Quaternion chestTargetRotation, IKSolverVR.Arm[] arms)
			{
				Quaternion rotation = Quaternion.Inverse(this.anchorRotation);
				Vector3 vector = rotation * (arms[0].position - this.headPosition);
				Vector3 vector2 = rotation * (arms[1].position - this.headPosition);
				Vector3 forward = Vector3.forward;
				forward.x += vector.x * Mathf.Abs(vector.x);
				forward.x += vector.z * Mathf.Abs(vector.z);
				forward.x += vector2.x * Mathf.Abs(vector2.x);
				forward.x -= vector2.z * Mathf.Abs(vector2.z);
				forward.x *= 5f;
				Quaternion lhs = Quaternion.FromToRotation(Vector3.forward, forward);
				chestTargetRotation = lhs * chestTargetRotation;
				Vector3 up = Vector3.up;
				up.x += vector.y;
				up.x -= vector2.y;
				up.x *= 0.5f;
				lhs = Quaternion.FromToRotation(Vector3.up, this.anchorRotation * up);
				chestTargetRotation = lhs * chestTargetRotation;
			}

			// Token: 0x060007D6 RID: 2006 RVA: 0x0002A6D8 File Offset: 0x00028AD8
			public void InverseTranslateToHead(IKSolverVR.Leg[] legs, bool limited, bool useCurrentLegMag, Vector3 offset, float w)
			{
				Vector3 vector = this.pelvis.solverPosition + (this.headPosition + offset - this.head.solverPosition) * w * (1f - this.pelvisPositionWeight);
				base.MovePosition((!limited) ? vector : this.LimitPelvisPosition(legs, vector, useCurrentLegMag, 2));
			}

			// Token: 0x060007D7 RID: 2007 RVA: 0x0002A748 File Offset: 0x00028B48
			private void TranslatePelvis(IKSolverVR.Leg[] legs, Vector3 deltaPosition, Quaternion deltaRotation, float w)
			{
				Vector3 solverPosition = this.head.solverPosition;
				deltaRotation = QuaTools.ClampRotation(deltaRotation, this.chestClampWeight, 2);
				Quaternion lhs = (w < 1f) ? Quaternion.Slerp(Quaternion.identity, this.pelvisRotationOffset, w) : this.pelvisRotationOffset;
				IKSolverVR.VirtualBone.RotateAroundPoint(this.bones, 0, this.pelvis.solverPosition, lhs * Quaternion.Slerp(Quaternion.identity, deltaRotation, w * this.bodyRotStiffness));
				deltaPosition -= this.head.solverPosition - solverPosition;
				Vector3 a = this.anchorRotation * Vector3.forward;
				a.y = 0f;
				float d = deltaPosition.y * 0.35f * this.headHeight;
				deltaPosition += a * d;
				base.MovePosition(this.LimitPelvisPosition(legs, this.pelvis.solverPosition + deltaPosition * w * this.bodyPosStiffness, false, 2));
			}

			// Token: 0x060007D8 RID: 2008 RVA: 0x0002A858 File Offset: 0x00028C58
			private Vector3 LimitPelvisPosition(IKSolverVR.Leg[] legs, Vector3 pelvisPosition, bool useCurrentLegMag, int it = 2)
			{
				if (useCurrentLegMag)
				{
					foreach (IKSolverVR.Leg leg in legs)
					{
						leg.currentMag = Vector3.Distance(leg.thigh.solverPosition, leg.lastBone.solverPosition);
					}
				}
				for (int j = 0; j < it; j++)
				{
					foreach (IKSolverVR.Leg leg2 in legs)
					{
						Vector3 b = pelvisPosition - this.pelvis.solverPosition;
						Vector3 vector = leg2.thigh.solverPosition + b;
						Vector3 vector2 = vector - leg2.position;
						float maxLength = (!useCurrentLegMag) ? leg2.mag : leg2.currentMag;
						Vector3 a = leg2.position + Vector3.ClampMagnitude(vector2, maxLength);
						pelvisPosition += a - vector;
					}
				}
				return pelvisPosition;
			}

			// Token: 0x060007D9 RID: 2009 RVA: 0x0002A958 File Offset: 0x00028D58
			private void Bend(IKSolverVR.VirtualBone[] bones, int firstIndex, int lastIndex, Quaternion targetRotation, float clampWeight, bool uniformWeight, float w)
			{
				if (w <= 0f)
				{
					return;
				}
				if (bones.Length == 0)
				{
					return;
				}
				int num = lastIndex + 1 - firstIndex;
				if (num < 1)
				{
					return;
				}
				Quaternion quaternion = QuaTools.FromToRotation(bones[lastIndex].solverRotation, targetRotation);
				quaternion = QuaTools.ClampRotation(quaternion, clampWeight, 2);
				float num2 = (!uniformWeight) ? 0f : (1f / (float)num);
				for (int i = firstIndex; i < lastIndex + 1; i++)
				{
					if (!uniformWeight)
					{
						num2 = Mathf.Clamp((float)((i - firstIndex + 1) / num), 0f, 1f);
					}
					IKSolverVR.VirtualBone.RotateAroundPoint(bones, i, bones[i].solverPosition, Quaternion.Slerp(Quaternion.identity, quaternion, num2 * w));
				}
			}

			// Token: 0x0400048F RID: 1167
			[Tooltip("The head target.")]
			public Transform headTarget;

			// Token: 0x04000490 RID: 1168
			[Tooltip("The pelvis target, useful with seated rigs.")]
			public Transform pelvisTarget;

			// Token: 0x04000491 RID: 1169
			[Tooltip("Positional weight of the head target.")]
			[Range(0f, 1f)]
			public float positionWeight = 1f;

			// Token: 0x04000492 RID: 1170
			[Tooltip("Rotational weight of the head target.")]
			[Range(0f, 1f)]
			public float rotationWeight = 1f;

			// Token: 0x04000493 RID: 1171
			[Tooltip("Positional weight of the pelvis target.")]
			[Range(0f, 1f)]
			public float pelvisPositionWeight;

			// Token: 0x04000494 RID: 1172
			[Tooltip("Determines how much the body will follow the position of the head.")]
			[Range(0f, 1f)]
			public float bodyPosStiffness = 0.55f;

			// Token: 0x04000495 RID: 1173
			[Tooltip("Determines how much the body will follow the rotation of the head.")]
			[Range(0f, 1f)]
			public float bodyRotStiffness = 0.1f;

			// Token: 0x04000496 RID: 1174
			[Tooltip("Determines how much the chest will rotate to the rotation of the head.")]
			[Range(0f, 1f)]
			public float chestRotationWeight = 0.2f;

			// Token: 0x04000497 RID: 1175
			[Tooltip("Clamps chest rotation.")]
			[Range(0f, 1f)]
			public float chestClampWeight = 0.5f;

			// Token: 0x04000498 RID: 1176
			[Tooltip("Clamps head rotation.")]
			[Range(0f, 1f)]
			public float headClampWeight = 0.6f;

			// Token: 0x04000499 RID: 1177
			[Tooltip("How much will the pelvis maintain it's animated position?")]
			[Range(0f, 1f)]
			public float maintainPelvisPosition = 0.2f;

			// Token: 0x0400049A RID: 1178
			[Tooltip("Will automatically rotate the root of the character if the head target has turned past this angle.")]
			[Range(0f, 180f)]
			public float maxRootAngle = 25f;

			// Token: 0x0400049E RID: 1182
			[HideInInspector]
			public Vector3 pelvisPositionOffset;

			// Token: 0x0400049F RID: 1183
			[HideInInspector]
			public Vector3 chestPositionOffset;

			// Token: 0x040004A0 RID: 1184
			[HideInInspector]
			public Vector3 headPositionOffset;

			// Token: 0x040004A1 RID: 1185
			[HideInInspector]
			public Quaternion pelvisRotationOffset = Quaternion.identity;

			// Token: 0x040004A2 RID: 1186
			[HideInInspector]
			public Quaternion chestRotationOffset = Quaternion.identity;

			// Token: 0x040004A3 RID: 1187
			[HideInInspector]
			public Quaternion headRotationOffset = Quaternion.identity;

			// Token: 0x040004A4 RID: 1188
			[HideInInspector]
			public Vector3 faceDirection;

			// Token: 0x040004A6 RID: 1190
			private Vector3 headPosition;

			// Token: 0x040004A7 RID: 1191
			private Quaternion headRotation = Quaternion.identity;

			// Token: 0x040004A8 RID: 1192
			private Quaternion anchorRelativeToHead = Quaternion.identity;

			// Token: 0x040004A9 RID: 1193
			private Quaternion pelvisRelativeRotation = Quaternion.identity;

			// Token: 0x040004AA RID: 1194
			private Quaternion chestRelativeRotation = Quaternion.identity;

			// Token: 0x040004AB RID: 1195
			private Vector3 headDeltaPosition;

			// Token: 0x040004AC RID: 1196
			private Quaternion pelvisDeltaRotation = Quaternion.identity;

			// Token: 0x040004AD RID: 1197
			private Quaternion chestTargetRotation = Quaternion.identity;

			// Token: 0x040004AE RID: 1198
			private const int pelvisIndex = 0;

			// Token: 0x040004AF RID: 1199
			private const int spineIndex = 1;

			// Token: 0x040004B0 RID: 1200
			private const int chestIndex = 2;

			// Token: 0x040004B1 RID: 1201
			private const int neckIndex = 3;

			// Token: 0x040004B2 RID: 1202
			private int headIndex;

			// Token: 0x040004B3 RID: 1203
			private float length;

			// Token: 0x040004B4 RID: 1204
			private bool hasNeck;

			// Token: 0x040004B5 RID: 1205
			private float headHeight;
		}

		// Token: 0x02000188 RID: 392
		[Serializable]
		public enum PositionOffset
		{
			// Token: 0x040004B7 RID: 1207
			Pelvis,
			// Token: 0x040004B8 RID: 1208
			Chest,
			// Token: 0x040004B9 RID: 1209
			Head,
			// Token: 0x040004BA RID: 1210
			LeftHand,
			// Token: 0x040004BB RID: 1211
			RightHand,
			// Token: 0x040004BC RID: 1212
			LeftFoot,
			// Token: 0x040004BD RID: 1213
			RightFoot,
			// Token: 0x040004BE RID: 1214
			LeftHeel,
			// Token: 0x040004BF RID: 1215
			RightHeel
		}

		// Token: 0x02000189 RID: 393
		[Serializable]
		public enum RotationOffset
		{
			// Token: 0x040004C1 RID: 1217
			Pelvis,
			// Token: 0x040004C2 RID: 1218
			Chest,
			// Token: 0x040004C3 RID: 1219
			Head
		}

		// Token: 0x0200018A RID: 394
		[Serializable]
		public class VirtualBone
		{
			// Token: 0x060007DA RID: 2010 RVA: 0x0002AA0E File Offset: 0x00028E0E
			public VirtualBone(Vector3 position, Quaternion rotation)
			{
				this.Read(position, rotation);
			}

			// Token: 0x060007DB RID: 2011 RVA: 0x0002AA1E File Offset: 0x00028E1E
			public void Read(Vector3 position, Quaternion rotation)
			{
				this.readPosition = position;
				this.readRotation = rotation;
				this.solverPosition = position;
				this.solverRotation = rotation;
			}

			// Token: 0x060007DC RID: 2012 RVA: 0x0002AA3C File Offset: 0x00028E3C
			public static void SwingRotation(IKSolverVR.VirtualBone[] bones, int index, Vector3 swingTarget, float weight = 1f)
			{
				if (weight <= 0f)
				{
					return;
				}
				Quaternion quaternion = Quaternion.FromToRotation(bones[index].solverRotation * bones[index].axis, swingTarget - bones[index].solverPosition);
				if (weight < 1f)
				{
					quaternion = Quaternion.Lerp(Quaternion.identity, quaternion, weight);
				}
				for (int i = index; i < bones.Length; i++)
				{
					bones[i].solverRotation = quaternion * bones[i].solverRotation;
				}
			}

			// Token: 0x060007DD RID: 2013 RVA: 0x0002AAC0 File Offset: 0x00028EC0
			public static float PreSolve(ref IKSolverVR.VirtualBone[] bones)
			{
				float num = 0f;
				for (int i = 0; i < bones.Length; i++)
				{
					if (i < bones.Length - 1)
					{
						bones[i].sqrMag = (bones[i + 1].solverPosition - bones[i].solverPosition).sqrMagnitude;
						bones[i].length = Mathf.Sqrt(bones[i].sqrMag);
						num += bones[i].length;
						bones[i].axis = Quaternion.Inverse(bones[i].solverRotation) * (bones[i + 1].solverPosition - bones[i].solverPosition);
					}
					else
					{
						bones[i].sqrMag = 0f;
						bones[i].length = 0f;
					}
				}
				return num;
			}

			// Token: 0x060007DE RID: 2014 RVA: 0x0002AB98 File Offset: 0x00028F98
			public static void RotateAroundPoint(IKSolverVR.VirtualBone[] bones, int index, Vector3 point, Quaternion rotation)
			{
				for (int i = index; i < bones.Length; i++)
				{
					if (bones[i] != null)
					{
						Vector3 point2 = bones[i].solverPosition - point;
						bones[i].solverPosition = point + rotation * point2;
						bones[i].solverRotation = rotation * bones[i].solverRotation;
					}
				}
			}

			// Token: 0x060007DF RID: 2015 RVA: 0x0002ABFC File Offset: 0x00028FFC
			public static void RotateBy(IKSolverVR.VirtualBone[] bones, int index, Quaternion rotation)
			{
				for (int i = index; i < bones.Length; i++)
				{
					if (bones[i] != null)
					{
						Vector3 point = bones[i].solverPosition - bones[index].solverPosition;
						bones[i].solverPosition = bones[index].solverPosition + rotation * point;
						bones[i].solverRotation = rotation * bones[i].solverRotation;
					}
				}
			}

			// Token: 0x060007E0 RID: 2016 RVA: 0x0002AC70 File Offset: 0x00029070
			public static void RotateBy(IKSolverVR.VirtualBone[] bones, Quaternion rotation)
			{
				for (int i = 0; i < bones.Length; i++)
				{
					if (bones[i] != null)
					{
						if (i > 0)
						{
							Vector3 point = bones[i].solverPosition - bones[0].solverPosition;
							bones[i].solverPosition = bones[0].solverPosition + rotation * point;
						}
						bones[i].solverRotation = rotation * bones[i].solverRotation;
					}
				}
			}

			// Token: 0x060007E1 RID: 2017 RVA: 0x0002ACE8 File Offset: 0x000290E8
			public static void RotateTo(IKSolverVR.VirtualBone[] bones, int index, Quaternion rotation)
			{
				Quaternion rotation2 = QuaTools.FromToRotation(bones[index].solverRotation, rotation);
				IKSolverVR.VirtualBone.RotateAroundPoint(bones, index, bones[index].solverPosition, rotation2);
			}

			// Token: 0x060007E2 RID: 2018 RVA: 0x0002AD14 File Offset: 0x00029114
			public static void SolveTrigonometric(IKSolverVR.VirtualBone[] bones, int first, int second, int third, Vector3 targetPosition, Vector3 bendNormal, float weight)
			{
				if (weight <= 0f)
				{
					return;
				}
				targetPosition = Vector3.Lerp(bones[third].solverPosition, targetPosition, weight);
				Vector3 vector = targetPosition - bones[first].solverPosition;
				float sqrMagnitude = vector.sqrMagnitude;
				if (sqrMagnitude == 0f)
				{
					return;
				}
				float directionMag = Mathf.Sqrt(sqrMagnitude);
				float sqrMagnitude2 = (bones[second].solverPosition - bones[first].solverPosition).sqrMagnitude;
				float sqrMagnitude3 = (bones[third].solverPosition - bones[second].solverPosition).sqrMagnitude;
				Vector3 bendDirection = Vector3.Cross(vector, bendNormal);
				Vector3 directionToBendPoint = IKSolverVR.VirtualBone.GetDirectionToBendPoint(vector, directionMag, bendDirection, sqrMagnitude2, sqrMagnitude3);
				Quaternion quaternion = Quaternion.FromToRotation(bones[second].solverPosition - bones[first].solverPosition, directionToBendPoint);
				if (weight < 1f)
				{
					quaternion = Quaternion.Lerp(Quaternion.identity, quaternion, weight);
				}
				IKSolverVR.VirtualBone.RotateAroundPoint(bones, first, bones[first].solverPosition, quaternion);
				Quaternion quaternion2 = Quaternion.FromToRotation(bones[third].solverPosition - bones[second].solverPosition, targetPosition - bones[second].solverPosition);
				if (weight < 1f)
				{
					quaternion2 = Quaternion.Lerp(Quaternion.identity, quaternion2, weight);
				}
				IKSolverVR.VirtualBone.RotateAroundPoint(bones, second, bones[second].solverPosition, quaternion2);
			}

			// Token: 0x060007E3 RID: 2019 RVA: 0x0002AE68 File Offset: 0x00029268
			private static Vector3 GetDirectionToBendPoint(Vector3 direction, float directionMag, Vector3 bendDirection, float sqrMag1, float sqrMag2)
			{
				float num = (directionMag * directionMag + (sqrMag1 - sqrMag2)) / 2f / directionMag;
				float y = (float)Math.Sqrt((double)Mathf.Clamp(sqrMag1 - num * num, 0f, float.PositiveInfinity));
				if (direction == Vector3.zero)
				{
					return Vector3.zero;
				}
				return Quaternion.LookRotation(direction, bendDirection) * new Vector3(0f, y, num);
			}

			// Token: 0x060007E4 RID: 2020 RVA: 0x0002AED0 File Offset: 0x000292D0
			public static void SolveFABRIK(IKSolverVR.VirtualBone[] bones, Vector3 startPosition, Vector3 targetPosition, float weight, float minNormalizedTargetDistance, int iterations, float length)
			{
				if (weight <= 0f)
				{
					return;
				}
				if (minNormalizedTargetDistance > 0f)
				{
					Vector3 a = targetPosition - startPosition;
					float magnitude = a.magnitude;
					targetPosition = startPosition + a / magnitude * Mathf.Max(length * minNormalizedTargetDistance, magnitude);
				}
				for (int i = 0; i < iterations; i++)
				{
					bones[bones.Length - 1].solverPosition = Vector3.Lerp(bones[bones.Length - 1].solverPosition, targetPosition, weight);
					for (int j = bones.Length - 2; j > -1; j--)
					{
						bones[j].solverPosition = IKSolverVR.VirtualBone.SolveFABRIKJoint(bones[j].solverPosition, bones[j + 1].solverPosition, bones[j].length);
					}
					bones[0].solverPosition = startPosition;
					for (int k = 1; k < bones.Length; k++)
					{
						bones[k].solverPosition = IKSolverVR.VirtualBone.SolveFABRIKJoint(bones[k].solverPosition, bones[k - 1].solverPosition, bones[k - 1].length);
					}
				}
				for (int l = 0; l < bones.Length - 1; l++)
				{
					IKSolverVR.VirtualBone.SwingRotation(bones, l, bones[l + 1].solverPosition, 1f);
				}
			}

			// Token: 0x060007E5 RID: 2021 RVA: 0x0002B014 File Offset: 0x00029414
			private static Vector3 SolveFABRIKJoint(Vector3 pos1, Vector3 pos2, float length)
			{
				return pos2 + (pos1 - pos2).normalized * length;
			}

			// Token: 0x060007E6 RID: 2022 RVA: 0x0002B03C File Offset: 0x0002943C
			public static void SolveCCD(IKSolverVR.VirtualBone[] bones, Vector3 targetPosition, float weight, int iterations)
			{
				if (weight <= 0f)
				{
					return;
				}
				for (int i = 0; i < iterations; i++)
				{
					for (int j = bones.Length - 2; j > -1; j--)
					{
						Vector3 fromDirection = bones[bones.Length - 1].solverPosition - bones[j].solverPosition;
						Vector3 toDirection = targetPosition - bones[j].solverPosition;
						Quaternion quaternion = Quaternion.FromToRotation(fromDirection, toDirection);
						if (weight >= 1f)
						{
							IKSolverVR.VirtualBone.RotateBy(bones, j, quaternion);
						}
						else
						{
							IKSolverVR.VirtualBone.RotateBy(bones, j, Quaternion.Lerp(Quaternion.identity, quaternion, weight));
						}
					}
				}
			}

			// Token: 0x040004C4 RID: 1220
			public Vector3 readPosition;

			// Token: 0x040004C5 RID: 1221
			public Quaternion readRotation;

			// Token: 0x040004C6 RID: 1222
			public Vector3 solverPosition;

			// Token: 0x040004C7 RID: 1223
			public Quaternion solverRotation;

			// Token: 0x040004C8 RID: 1224
			public float length;

			// Token: 0x040004C9 RID: 1225
			public float sqrMag;

			// Token: 0x040004CA RID: 1226
			public Vector3 axis;
		}
	}
}
